动态规划算法实验报告材料.docx
《动态规划算法实验报告材料.docx》由会员分享,可在线阅读,更多相关《动态规划算法实验报告材料.docx(26页珍藏版)》请在冰豆网上搜索。
动态规划算法实验报告材料
实验标题
1、矩阵连乘2、最长公共子序列3、最大子段和
4、凸多边形最优三角剖分5、流水作业调度
6、0-1背包问题7、最优二叉搜索树
实验目的
掌握动态规划法的基本思想和算法设计的基本步骤。
实验内容与源码
1、矩阵连乘
#include
#include
usingnamespacestd;
constintsize=4;
//ra,ca和rb,cb分别表示矩阵A和B的行数和列数
voidmatriMultiply(inta[][4],intb[][4],intc[][4],intra,intca,intrb,intcb)
{
if(ca!
=rb)cerr<<"矩阵不可乘";
for(inti=0;ifor(intj=0;j{
intsum=a[i][0]*b[0][j];
for(intk=1;ksum+=a[i][k]*b[k][j];
c[i][j]=sum;
}
}
voidMatrixChain(int*p,intn,intm[][4],ints[][4])
{
for(inti=1;i<=n;i++)m[i][i]=0;//对角线
for(intr=2;r<=n;r++)//外维
for(inti=1;i<=n-r+1;i++)//上三角
{
intj=i+r-1;
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(intk=i+1;k{
intt=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t{
m[i][j]=t;
s[i][j]=k;
}
}
}
}
voidTraceback(inti,intj,ints[][4])
{
if(i==j)
{
cout<<"A"<
}
elseif(i+1==j)
{
cout<<"(A"<
}
else
{
cout<<"(";
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
cout<<")";
}
}
intmain()
{
intw;
cout<<"矩阵个数:
";
cin>>w;
intp[w],s[w][w];
cout<<"输入矩阵A1维数:
";
cin>>p[0]>>p[1];
for(inti=2;i<=w;i++)
{
intm=p[i-1];
cout<<"输入矩阵A"<
";
cin>>p[i-1]>>p[i];
if(p[i-1]!
=m)
{
cout<"<exit
(1);
}
}
Traceback(1,w,s);
return0;
}
运行结果
2、最长公共子序列
#include
#include
#defineN100
usingnamespacestd;
//str1存储字符串x,str2存储字符串y
charstr1[N],str2[N];
//lcs存储最长公共子序列
charlcs[N];
//c[i][j]存储str1[1...i]与str2[1...j]的最长公共子序列的长度
intc[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]
intflag[N][N];
//求长度
intLCSLength(char*x,char*y)
{
inti,j;
//分别取得x,y的长度
intm=strlen(x);
intn=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;
}
elseif(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;
}
}
returnc[m][n];
}
//求出最长公共子序列
char*getLCS(char*x,char*y,intlen,char*lcs)
{
inti=strlen(x);
intj=strlen(y);
while(i&&j)
{
if(flag[i][j]==0)
{
lcs[--len]=x[i-1];
i--;
j--;
}
elseif(flag[i][j]==1)
i--;
else
j--;
}
returnlcs;
}
intmain()
{
inti;
cout<<"请输入字符串x:
"<cin>>str1;
cout<<"请输入字符串y:
"<cin>>str2;
intlcsLen=LCSLength(str1,str2);
cout<<"最长公共子序列长度:
"<char*p=getLCS(str1,str2,lcsLen,lcs);
cout<<"最长公共子序列为:
";
for(i=0;icout<return0;
}
运行结果
3、最大子段和
//分治法求最大子段和
#include
usingnamespacestd;
intMaxSubSum(int*a,intleft,intright)
{
intsum=0;
if(left==right)sum=a[left]>0?
a[left]:
0;
else
{
intcenter=(left+right)/2;
//最大子段和在左边
intleftsum=MaxSubSum(a,left,center);
//最大子段和在右边
intrightsum=MaxSubSum(a,center+1,right);
//最大子段和在中间
ints1=0;
intlefts=0;
for(inti=center;i>=left;i--)
{
lefts+=a[i];
if(lefts>s1)s1=lefts;
}
ints2=0;
intrights=0;
for(inti=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;
}
returnsum;
}
intMaxSum(int*a,intn)
{
returnMaxSubSum(a,1,n-1);
}
intmain()
{
inta[8]={2,-3,-5,4,1,7,1,-5};
cout<<"最大子段和为:
"<return0;
}
//动态规划法
#include
usingnamespacestd;
intMaxSum(int*a,intn)
{
intsum=0,b=0;
for(inti=1;i{
if(b>0)b+=a[i];
elseb=a[i];
if(b>sum)sum=b;
}
returnsum;
}
intmain()
{
inta[8]={2,-3,-5,4,1,7,1,-5};
cout<<"最大子段和为:
"<return0;
}
运行结果
4、凸多边形最优三角剖分
#include
#include
#include
#defineN50
usingnamespacestd;
structpoint
{
intx;
inty;
};
intdistance(pointX,pointY)//两点距离
{
intdis=(Y.x-X.x)*(Y.x-X.x)+(Y.y-X.y)*(Y.y-X.y);
return(int)sqrt(dis);
}
intw(pointa,pointb,pointc)//权值
{
returndistance(a,b)+distance(b,c)+distance(a,c);
}
boolJudgeInput()//判断是否能构成凸多边形
{
point*v;//记录凸多边形各顶点坐标
int*total;//记录坐标在直线方程中的值
intm,a,b,c;
cout<<"请输入凸多边形顶点个数:
";
cin>>m;
intM=m-1;
for(inti=0;i{
cout<<"输入顶点v"<
";
cin>>v[i].x>>v[i].y;
}
//根据顶点坐标判断是否能构成一个凸多边形
for(intj=0;j{
intp=0;
intq=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(intk=0;k{
total[k]=a*v[k].x-b*v[k].y+c;
if(total[k]>0)
{
p=p+1;
}
elseif(total[k]<0)
{
q=q+1;
}
}
if((p>0&&q>0)||(p==0&&q==0))
{
cout<<"无法构成凸多边形!
"<exit
(1);
}
}
}
boolminWeightTriangulation()//计算最优值算法
{
intM;
int**t,**s;
point*v;
for(inti=1;i<=M;i++)
t[i][i]=0;
for(intr=2;r<=M;r++)
for(inti=1;i<=M-r+1;i++)
{
intj=i+r-1;
t[i][j]=t[i+1][j]+w(v[i-1],v[i],v[j]);
s[i][j]=i;
for(intk=i+1;k
{
intu=t[i][k]+t[k+1][j]+w(v[i-1],v[k],v[j]);
if(u{
t[i][j]=u;
s[i][j]=k;
}
}
}
returntrue;
}
voidTraceback(inti,intj,int**s)
{
if(i==j)
return;
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
cout<<"三角形:
v"<}
intmain()
{
int**s;//记录最优三角剖分中所有三角形信息
int**t;//记录最优三角剖分所对应的权函数值
point*v;//记录凸多边形各顶点坐标
int*total;//记录坐标在直线方程中的值
intM=0;
t=newint*[N];
s=newint*[N];
for(inti=0;i{
t[i]=newint[N];
s[i]=newint[N];
}
v=newpoint[N];
total=newint[N];
if(JudgeInput())
{
if(minWeightTriangulation())
{
Traceback(1,M,s);
cout<cout<<"最优权值之和为:
"<}
}
return0;
}
运行结果:
5、流水作业调度
#include
#defineN100
usingnamespacestd;
classJobtype
{
public:
/*intoperator<=(Jobtypea)const
{
return(key<=a.key);
}*/
intkey;
intindex;
booljob;
};
voidsort(Jobtype*d,intn)
{
inti,j;
Jobtypetemp;
boolexchange;//交换标志
for(i=0;iexchange=false;//本趟排序开始前,交换标志应为假
for(j=n-1;j>=i;j--)
if(d[j+1].keytemp=d[j+1];
d[j+1]=d[j];
d[j]=temp;
exchange=true;//发生了交换,故将交换标志置为真
}
if(!
exchange)//本趟排序未发生交换,提前终止算法
return;
}
}
intFlowShop(intn,int*a,int*b,int*c)
{
Jobtype*d=newJobtype[n];
for(inti=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);;
intj=0;
intk=n-1;
for(inti=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(inti=1;i{
j+=a[c[i]];
k=jk+b[c[i]]:
j+b[c[i]];
}
deleted;//回收空间
returnk;//返回调度时间
}
intmain()
{
intn,*a,*b,*c;
cout<<"作业数:
";
cin>>n;
Jobtype*d=newJobtype[N];
a=newint[N];
b=newint[N];
c=newint[N];
cout<<"请输入作业号和时间:
";
for(inti=0;i{
cin>>d[i].index>>d[i].key;
}
cout<intk=FlowShop(n,a,b,c);
cout<<"\n调度时间:
"<cout<<"最优调度序列:
";
for(inti=0;i{
cout<}
return0;
}
运行结果:
6、0-1背包问题
#include
#include
usingnamespacestd;
constintC=10;//容量
constintN=5;//个数
intmax(constinta,constintb)
{
returna>b?
a:
b;
}
intmin(constinta,constintb)
{
returna
a:
b;
}
/*
m为记录数组m[i][j]代表在剩有j容量的条件下,从i开始往后的物品中可以取得的最大价值
w为重量数组,v为价值数组
n为物品个数,c为开始容量
则m[1][c]即此背包能剩下的最大价值
*/
voidknapsack(int**m,intn,intc,int*w,int*v)
{
intjMax=min(w[n]-1,c);//前n-1个物品
for(intj=0;j<=jMax;j++)
m[n][j]=0;
for(intj=w[n];j<=c;j++)
m[n][j]=v[n];
for(inti=n-1;i>1;i--)
{
jMax=min(w[i]-1,c);
for(intj=0;j<=jMax;j++)
m[i][j]=m[i+1][j];
for(intj=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表示能装
voidtraceback(int**m,intn,intc,int*x,int*w)
{
for(inti=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;
}
intmain()
{
int*v=newint[N+1];
int*w=newint[N+1];
int**m=newint*[N+1];
int*x=newint[N+1];
for(inti=0;i{
m[i]=newint[C+1];
}
cout<<"输入重量序列,"<for(inti=1;i<=N;i++)
cin>>w[i];
cout<<"输入价值序列,"<for(inti=1;i<=N;i++)
cin>>v[i];
knapsack(m,N,C,w,v);
traceback(m,N,C,x,w);
cout<<"最优值:
"<cout<<"是否装入背包的情况:
";
for(inti=1;i<=N;i++)
{
cout<}
for(inti=0;i{
deletem[i];
}
delete[]m;
return0;
}
运行结果
7、最优二叉搜索树
#include
#include
#include
#defineN100
usingnamespacestd;
constdoubleMAX=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的
voidOptimalBinarySearchTree(double*a,double*b,intn)
{
ints[N][N];
doublem[N][N];
doublew[N][N];
inti,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++)
{
doublek=m[i][r-1]+w[i][j]+m[r+1][j];
if(k{
m[i][j]=k;
s[i][j]=k;
}
}
}
}
cout<}
intmain()
{
doublea[N],b[N];
intn;
doublesum=0;
inti,j,l;