动态规划算法实验报告

时间:22-09-12 网友

实验标题

1、矩阵连乘 2、最长公共子序列 3、最大子段和

4、凸多边形最优三角剖分 5、流水作业调度

6、0-1背包问题 7、最优二叉搜索树

实验目的

掌握动态规划法的基本思想和算法设计的基本步骤。

实验内容与源码

1、矩阵连乘

#include

#include

using namespace std;

const int size=4;

//ra,ca和rb,cb分别表示矩阵A和B的行数和列数

void matriMultiply(int a[][4],int b[][4],int c[][4],int ra ,int ca,int rb ,int cb )

{

if(ca!=rb) cerr<<"矩阵不可乘";

for(int i=0;i

for(int j=0;j

{

int sum=a[i][0]*b[0][j];

for(int k=1;k

sum+=a[i][k]*b[k][j];

c[i][j]=sum;

}

}

void MatrixChain(int *p,int n,int m[][4],int s[][4])

{

for(int i=1;i<=n;i++) m[i][i]=0;//对角线

for(int r=2;r<=n;r++)//外维

for(int i=1;i<=n-r+1;i++)//上三角

{

int j=i+r-1;

m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];

s[i][j]=i;

for(int k=i+1;k

{

int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];

if(t

{

m[i][j]=t;

s[i][j]=k;

}

}

}

}

void Traceback(int i,int j,int s[][4])

{

if(i == j)

{

cout<<"A"<

}

else if(i+1 == j)

{

cout<<"(A"<

}

else

{

cout<<"(";

Traceback(i,s[i][j],s);

Traceback(s[i][j]+1,j,s);

cout<<")";

}

}

int main()

{

int w;

cout<<"矩阵个数:";

cin>>w;

int p[w],s[w][w];

cout<<"输入矩阵A1维数:";

cin>>p[0]>>p[1];

for(int i=2 ; i<=w ; i++)

{

int m = p[i-1];

cout<<"输入矩阵A"<

cin>>p[i-1]>>p[i];

if(p[i-1] != m)

{

cout<

exit(1);

}

}

Traceback(1,w,s);

return 0;

}

运行结果

word/media/image1.jpeg

2、最长公共子序列

#include

#include

#define N 100

using namespace std;

//str1存储字符串x,str2存储字符串y

char str1[N],str2[N];

//lcs存储最长公共子序列

char lcs[N];

//c[i][j]存储str1[1...i]与str2[1...j]的最长公共子序列的长度

int c[N][N];

//flag[i][j]==0为str1[i]==str2[j]

//flag[i][j]==1为c[i-1][j]>=s[i][j-1]

//flag[i][j]==-1为c[i-1][j]

int flag[N][N];

//求长度

int LCSLength(char *x, char *y)

{

int i,j;

//分别取得x,y的长度

int m = strlen(x);

int n = strlen(y);

for(i=1;i<=m;i++)

c[i][0] = 0;

for(i=0;i<=n;i++)

c[0][i] = 0;

for(i=1;i<=m;i++)

for(j=1;j<=n;j++)

{

if(x[i-1]==y[j-1])

{

c[i][j] = c[i-1][j-1] +1;

flag[i][j] = 0;

}

else if(c[i-1][j]>=c[i][j-1])

{

c[i][j] = c[i-1][j];

flag[i][j] = 1;

}

else

{

c[i][j] = c[i][j-1];

flag[i][j] = -1;

}

}

return c[m][n];

}

//求出最长公共子序列

char* getLCS(char *x, char *y,int len,char *lcs)

{

int i = strlen(x);

int j = strlen(y);

while(i&&j)

{

if(flag[i][j]==0)

{

lcs[--len] = x[i-1];

i--;

j--;

}

else if(flag[i][j]==1)

i--;

else

j--;

}

return lcs;

}

int main()

{

int i;

cout<<"请输入字符串x:"<

cin>>str1;

cout<<"请输入字符串y:"<

cin>>str2;

int lcsLen = LCSLength(str1,str2);

cout<<"最长公共子序列长度:"<

char *p = getLCS(str1,str2,lcsLen,lcs);

cout<<"最长公共子序列为:";

for(i=0;i

cout<

return 0;

}

运行结果

word/media/image2.jpeg

3、最大子段和

//分治法求最大子段和

#include

using namespace std;

int MaxSubSum(int *a,int left,int right)

{

int sum=0;

if(left==right) sum=a[left]>0?a[left]:0;

else

{

int center = (left+right)/2;

//最大子段和在左边

int leftsum=MaxSubSum(a,left,center);

//最大子段和在右边

int rightsum=MaxSubSum(a,center+1,right);

//最大子段和在中间

int s1=0;

int lefts=0;

for(int i=center;i>=left;i--)

{

lefts+=a[i];

if(lefts>s1) s1=lefts;

}

int s2=0;

int rights=0;

for(int i=center+1;i<=right;i++)

{

rights+=a[i];

if(rights>s2) s2=rights;

}

sum=s1+s2;//前后子段和相加

//判断最大子段和

if(sum>leftsum)sum=leftsum;

if(sum>rightsum) sum=rightsum;

}

return sum;

}

int MaxSum(int *a,int n)

{

return MaxSubSum(a,1,n-1);

}

int main()

{

int a[8]={2,-3,-5,4,1,7,1,-5};

cout<<"最大子段和为:"<

return 0;

}

//动态规划法

#include

using namespace std;

int MaxSum(int *a,int n)

{

int sum=0,b=0;

for(int i=1;i

{

if(b>0) b+=a[i];

else b=a[i];

if(b>sum) sum=b;

}

return sum;

}

int main()

{

int a[8]={2,-3,-5,4,1,7,1,-5};

cout<<"最大子段和为:"<

return 0;

}

运行结果

word/media/image3.jpeg

4、凸多边形最优三角剖分

#include

#include

#include

#define N 50

using namespace std;

struct point

{

int x;

int y;

};

int distance(point X, point Y)//两点距离

{

int dis = (Y.x-X.x)*(Y.x-X.x) + (Y.y-X.y)*(Y.y-X.y);

return (int)sqrt(dis);

}

int w(point a, point b, point c)//权值

{

return distance(a,b) + distance(b,c) + distance(a,c);

}

bool JudgeInput()//判断是否能构成凸多边形

{

point *v; //记录凸多边形各顶点坐标

int *total; //记录坐标在直线方程中的值

int m,a,b,c;

cout<<"请输入凸多边形顶点个数:";

cin>>m;

int M = m-1;

for(int i=0 ; i

{

cout<<"输入顶点v"<

cin>>v[i].x>>v[i].y;

}

//根据顶点坐标判断是否能构成一个凸多边形

for(int j=0 ; j

{

int p = 0;

int q = 0;

if(m-1 == j)

{

a = v[m-1].y - v[0].y;

b = v[m-1].x - v[0].y;

c = b * v[m-1].y - a * v[m-1].x;

}

else

{

a = v[j].y - v[j+1].y;

b = v[j].x - v[j+1].x;

c = b * v[j].y - a * v[j].x;

}

for(int k=0 ; k

{

total[k] = a * v[k].x - b * v[k].y + c;

if(total[k] > 0)

{

p = p+1;

}

else if(total[k] < 0)

{

q = q+1;

}

}

if((p>0 && q>0) || (p==0 && q==0))

{

cout<<"无法构成凸多边形!"<

exit(1);

}

}

}

bool minWeightTriangulation()//计算最优值算法

{

int M;

int **t, **s;

point *v;

for(int i=1 ; i<=M ; i++)

t[i][i] = 0;

for(int r=2 ; r<=M ; r++)

for(int i=1 ; i<=M-r+1 ; i++)

{

int j = i+r-1;

t[i][j] = t[i+1][j] + w(v[i-1],v[i],v[j]);

s[i][j] = i;

for(int k=i+1 ; k

{

int u = t[i][k] + t[k+1][j] + w(v[i-1],v[k],v[j]);

if(u < t[i][j])

{

t[i][j] = u;

s[i][j] = k;

}

}

}

return true;

}

void Traceback(int i, int j, int **s)

{

if(i == j)

return;

Traceback(i,s[i][j],s);

Traceback(s[i][j]+1,j,s);

cout<<"三角形:v"<

}

int main()

{

int **s; //记录最优三角剖分中所有三角形信息

int **t; //记录最优三角剖分所对应的权函数值

point *v; //记录凸多边形各顶点坐标

int *total; //记录坐标在直线方程中的值

int M=0;

t = new int *[N];

s = new int *[N];

for(int i=0 ; i

{

t[i] = new int[N];

s[i] = new int[N];

}

v = new point[N];

total = new int[N];

if(JudgeInput())

{

if(minWeightTriangulation())

{

Traceback(1,M,s);

cout<

cout<<"最优权值之和为:"<

}

}

return 0;

}

运行结果:

word/media/image4.jpeg

5、流水作业调度

#include

#define N 100

using namespace std;

class Jobtype

{

public:

/* int operator<=(Jobtype a)const

{

return(key<=a.key);

}*/

int key;

int index;

bool job;

};

void sort(Jobtype *d,int n)

{

int i,j;

Jobtype temp;

bool exchange; //交换标志

for(i = 0;i < n;i ++){ //最多做n-1趟排序

exchange = false; //本趟排序开始前,交换标志应为假

for(j = n - 1;j >= i;j --)

if(d[j+1].key < d[j].key){

temp = d[j+1];

d[j+1] = d[j];

d[j] = temp;

exchange=true; //发生了交换,故将交换标志置为真

}

if(!exchange) //本趟排序未发生交换,提前终止算法

return;

}

}

int FlowShop(int n,int *a,int *b,int *c)

{

Jobtype *d = new Jobtype[n];

for(int i=0;i

{

d[i].key=a[i]>b[i]?b[i]:a[i];// 执行时间

d[i].job=a[i]<=b[i];// 作业组

d[i].index=i;//作业序号

}

sort(d,n);;

int j=0;

int k=n-1;

for(int i=0;i

{

if(d[i].job)

{

c[j++]=d[i].index;

}

else

{

c[k--]=d[i].index;

}

}

j=a[c[0]];

k=j+b[c[0]];

for(int i=1;i

{

j+=a[c[i]];

k=j

}

delete d;//回收空间

return k;//返回调度时间

}

int main()

{

int n,*a,*b,*c;

cout<<"作业数:";

cin>>n;

Jobtype *d = new Jobtype[N];

a=new int[N];

b=new int[N];

c=new int[N];

cout<<"请输入作业号和时间:";

for(int i=0;i

{

cin>>d[i].index>>d[i].key;

}

cout << endl;

int k=FlowShop(n,a,b,c);

cout<<"\n调度时间:"<

cout<<"最优调度序列:";

for (int i = 0; i < n; i++) // 输出最优调度序列

{

cout << c[i] << " ";

}

return 0;

}

运行结果:

word/media/image5.jpeg

6、0-1背包问题

#include

#include

using namespace std;

const int C=10;//容量

const int N=5;//个数

int max(const int a,const int b)

{

return a>b?a:b;

}

int min(const int a,const int b)

{

return a

}

/*

m为记录数组 m[i][j]代表在剩有j容量的条件下,从i开始往后的物品中可以取得的最大价值

w为重量数组,v为价值数组

n为物品个数,c为开始容量

则m[1][c]即此背包能剩下的最大价值

*/

void knapsack(int **m,int n, int c,int *w, int *v)

{

int jMax = min(w[n]-1,c);//前n-1个物品

for(int j=0;j<=jMax;j++)

m[n][j]=0;

for(int j=w[n];j<=c;j++)

m[n][j]=v[n];

for(int i=n-1;i>1;i--)

{

jMax=min(w[i]-1,c);

for(int j=0;j<=jMax;j++)

m[i][j] = m[i+1][j];

for(int j=w[i];j<=c;j++)

m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]);

}

m[1][c]=m[2][c];

if(c>=w[1])

m[1][c]=max(m[1][c],m[2][c-w[1]]+v[1]);

}

//找出最优解,0表示不能装,1表示能装

void traceback(int **m,int n,int c,int *x,int *w)

{

for(int i=1;i

{

if(m[i][c]==m[i+1][c]) x[i]=0;

else

{

x[i]=1;

c-=w[i];

}

}

x[n]=(m[n][c]==0)?0:1;

}

int main()

{

int *v=new int[N+1];

int *w=new int[N+1];

int **m=new int* [N+1];

int *x=new int [N+1];

for(int i=0;i

{

m[i]=new int[C+1];

}

cout<<"输入重量序列,"<

for(int i=1;i<=N;i++)

cin>>w[i];

cout<<"输入价值序列,"<

for(int i=1;i<=N;i++)

cin>>v[i];

knapsack(m,N,C,w,v);

traceback(m,N,C,x,w);

cout<<"最优值:"<

cout<<"是否装入背包的情况:";

for(int i=1;i<=N;i++)

{

cout<

}

for(int i=0;i

{

delete m[i];

}

delete []m;

return 0;

}

运行结果

word/media/image6.jpeg

7、最优二叉搜索树

#include

#include

#include

#define N 100

using namespace std;

const double MAX = numeric_limits::max(); //double的最大值

//a[i]为结点i被访问的概率

//b[i]为“虚结点”i被访问的概率

//m[i][j]用来存放子树(i,j)的期望代价

//w[i][j]用来存放子树(i,j)的所有结点(包括虚结点)的a,b概率之和

//s[i][j]用来跟踪root的

void OptimalBinarySearchTree(double *a,double *b,int n)

{

int s[N][N];

double m[N][N];

double w[N][N];

int i,j,l,r;

for(i=1; i<=n+1; i++)

{

m[i][i-1] = b[i-1];

w[i][i-1] = b[i-1];

}

for(l=1; l<=n; l++)

{

for(i=1; i<=n-l+1; i++)

{

j = l+i-1;

m[i][j] = MAX;

w[i][j] = w[i][j-1] + a[j] +b[j];

for(r=i; r<=j; r++)

{

double k = m[i][r-1] + w[i][j] + m[r+1][j];

if(k

{

m[i][j] = k;

s[i][j] = k;

}

}

}

}

cout<

}

int main()

{

double a[N],b[N];

int n;

double sum = 0;

int i,j,l;

cout<<"请输入关键字的个数:"<

cin>>n;

cout<<"请输入每个关键字的概率:"<

for(i=1; i<=n; i++)

{

cin>>a[i];

sum += a[i];

}

cout<<"请输入每个虚拟键的概率:"<

for(i=0; i<=n; i++)

{

cin>>b[i];

sum += b[i];

}

if(abs(sum-1)>0.01)

{

cout<<"输入的概率和不为1,请重新输入"<

}

cout<<"最优二叉查找树的期望搜索代价为:";

OptimalBinarySearchTree(a,b,n);

return 0;

}

运行结果:

word/media/image7.jpeg

实验总结

通过实现动态规划的这个题目,对动态规划算法有了进一步的了解。先分析问题,判断是否具有最优子结果和重叠字问题的性质。

《动态规划算法实验报告》相关文档:

动态规划算法实验报告09-12

动态规划的应用场景与算法09-12

算法分析复习题目及答案.09-12

动态规划(dp算法)09-12

2023年通信算法工程师岗位职责10-11

Python最优化算法实战学习笔记10-27

数据挖掘算法工程师职位描述与岗位职责10-29

控制算法工程师的工作职责10-31

控制算法工程师的具体职责范围(精选27篇)10-31

控制算法工程师的基本职责(通用16篇)10-31

Top