算法实验3报告Word格式文档下载.docx
《算法实验3报告Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《算法实验3报告Word格式文档下载.docx(13页珍藏版)》请在冰豆网上搜索。
…>
TK(1<
=i<
=K)。
已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
四、算法思想分析
动态规划法的定义:
在求解问题中,对于每一步决策,列出各种可能的局部解,再依据某种判定条件,舍弃那些肯定不能得到最优解的局部解,在每一步都经过筛选,以每一步都是最优解来保证全局是最优解。
动态规划通常应用于最优化问题,即做出一组选择以达到一个最优解。
关键是存储子问题的每一个解,以备它重复出现
动态规划设计一般要经历以下几个步骤:
1、划分阶段:
按照问题的时间或空间特征,把问题分为若干个阶段。
2、确定状态:
将问题发展到各个阶段时所处的各种客观情况用不同的状态表示出来。
3、确定决策并写出状态转移方程:
因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态,所以如果确定了决策,状态转移方程也就可以写出。
4、寻找边界条件:
给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
5、程序设计实现:
动态规划的主要难点在于理论上的设计,一旦设计完成,实现部分就会非常简单。
背包问题
1、减小规模
m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。
m(i+1,j)可选择物品为i+1,…,n时0-1背包问题的最优值。
…
m(n,j)可选择物品为n时0-1背包问题的最优值。
规模已经为1
2、推导递归式,判断第i件?
1)不放,背包当前产生价值仍为m(i+1,j);
2)放入,调整背包容量j-wi,背包当前产生价值为m(i+1,j-wi)+Vi
由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下:
合唱队形
算法分析:
分别从左到右求最大上升子序列,从右到左求最大下降子序列,再枚举中间最高的一个人。
算法时间复杂度O(N2)。
思路:
递推关系式
b[i]=max{b[j](1<
=j<
i)|a[i]>
a[j]}+1
c[i]=max{c[j](i<
N)|a[i]>
a[j]}+1
合唱队人数=max{b[i]+c[i]}-1
(第i个人被重复计算了一次)
出列人数=N-合唱队人数
=N-(max{b[i]+c[i]}-1)
i
1
2
3
4
5
6
7
8
a[i]
186
150
200
160
130
197
220
b[i]
c[i]
b[i]+c[i]
五、算法源代码及用户屏幕
(1)编写一个简单的程序,解决0-1背包问题。
#include"
stdlib.h"
stdio.h"
iostream.h"
#defineN5
#defineC10
intmax(intp,intq)
{
if(p>
=q)
{
returnp;
}
elseif(p<
q)
returnq;
}
intmin(intm,intn)
if(m<
=n)
returnm;
elseif(m>
n)
returnn;
inti=0,j=0;
voidKnapSack(intv[],intw[],intc,intn,intm[][11])
intjMax=min(w[n]-1,c);
for(j=0;
j<
=jMax;
j++)/*m(n,j)=00=<
w[n]*/
m[n][j]=0;
for(j=w[n];
=c;
j++)/*m(n,j)=v[n]j>
=w[n]*/
m[n][j]=v[n];
for(i=n-1;
i>
1;
i--)
{
intjMax=min(w[i]-1,c);
j++)/*m(i,j)=m(i+1,j)0=<
w[i]*/
{
m[i][j]=m[i+1][j];
}
for(j=w[i];
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]);
voidtraceback(intm[][11],intw[],intc,intn,intx[])
for(i=1;
i<
n;
i++)
if(m[i][c]==m[i+1][c])
x[i]=0;
else
x[i]=1;
c=c-w[i];
x[n]=(m[n][c]>
0?
1:
0);
voidmain()
intn=N,c=C,w[N+1],v[N+1];
intm[N+1][C+1]={0};
intx[N+1]={0};
printf("
Pleaseinputw[%d]\n"
n);
=5;
scanf("
%d"
&
w[i]);
Pleaseinputv[%d]\n"
scanf("
v[i]);
KnapSack(v,w,c,n,m);
traceback(m,w,c,n,x);
m[1][10]=%d\n"
m[1][10]);
printf("
%2d"
x[i]);
cout<
<
endl;
}
(2)合唱队形安排。
#include<
stdio.h>
string.h>
iostream.h>
#include<
iomanip.h>
#defineMAXN200
intmain()
intn,a[MAXN],b[MAXN],c[MAXN],i,j,max;
intp[MAXN],x[MAXN];
"
请输入N的值"
&
n);
请输入身高"
for(i=1;
i<
=n;
i++)
a[i]);
memset(b,0,sizeof(a));
memset(c,0,sizeof(c));
/*左侧的最长上升子序列*/
b[1]=1;
p[1]=0;
for(i=2;
max=0;
for(j=i-1;
j>
=1;
j--)
if(a[j]<
a[i]&
&
b[j]+1>
max)
{
max=b[j];
p[i]=j;
}
b[i]=max+1;
max=b[1];
for(i=2;
=n;
if(b[i]>
max)
max=b[i];
/*求右侧的最长上升子序列*/
c[n]=1;
//x[1]=0;
for(i=n-1;
i>
0;
i--)
{max=0;
for(j=i+1;
j<
j++)
c[j]+1>
max=c[j];
//x[i]=j;
c[i]=max+1;
/*枚举求最长队形*/
max=b[1]+c[1];
{if(b[i]+c[i]>
max=b[i]+c[i];
****************************************************************"
出列人数为"
;
n-max+1<
("
\n"
);
i:
"
setw(5)<
i;
//空格数
a[i]"
a[i];
b[i]"
b[i];
c[i]"
c[i];
cout<
/*cout<
p[i]"
for(i=1;
p[i];
x[i]"
x[i];
*/
return0;
六、实验过程分析
掌握设计动态规划算法的步骤。
(1)找出最优解的性质,并刻划其结构特征。
(2)递归地定义最优值。
(3)以自底向上的方式计算出最优值。
(4)根据计算最优值时得到的信息,构造最优解。
动态规划算法的基本要素如下
最优子结构:
某个问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质
最优子结构是问题能用动态规划算法求解的前提。
重叠子问题:
递归算法求解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。
这种性质称为子问题的重叠性质。
动态规划算法对每一个子问题只解一次,而后将其解保存在一个表格中,当再次需要解此子问题时,只是简单地用常数时间查看一下结果。
通常不同的子问题个数随问题的大小呈多项式增长。
因此用动态规划算法只需要多项式时间,从而获得较高的解题效率。
备忘录方法:
备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解。
步骤:
为每个问题建立一个记录项,初值设为一个特殊值(表未求解)
每个待求解子问题,首先查记录项,有解答则直接选取,否则求解该子问题。