深圳大学实验报告课程名称:算法分析与复杂性理论
实验名称:实验四动态规划
学院:计算机与软件学院专业:软件工程
报告人:文成学号:2150230509班级:学术型
同组人:无
指导教师:杨烜
实验时间:2015/11/5——2015/11/18
实验报告提交时间:2015/11/18
教务处制
一. 实验目的与实验内容
实验目的:
(1) 掌握动态规划算法设计思想。
(2) 掌握背包问题的动态规划解法。
实验内容:
1.编写背包问题的动态规划求解代码。
2.背包容量为W ,物品个数为n ,随机产生n 个物品的体积(物品的体积不可大于W )与价值,求解该实例的最优解。
3. 分别针对以下情况求解 第一组:(n=10,W=10),(n=10,W=20),(n=10,W=30) 第二组:(n=20,W=10),(n=20,W=20),(n=20,W=30) 第三组:(n=30,W=10),(n=30,W=20),(n=30,W=30)
4. 画出三组实验的时间效率的折线图,其中x 轴是W 的值,y 轴是所花费的时间,用不同的颜色表示不同n 所花费的时间。
二.实验步骤与结果
背包问题的问题描述:
给定n 种物品和一个背包。
物品i 的重量是
i w ,
其价值为i v ,
背包容量为C 。
问应该如何选择装入背包的物品,使得装入背包中物品的总价值最大?
背包问题的算法思想:
考虑一个由前i 个物品(1<=i<=n )定义的实例,物品的重量分别为w1,…,w2、价值分别为v1,…,vi ,背包的承重量为j (1<=j<=w )。
设v[i,j]为该实例的最优解的物品总价值,也就是说,是能够放进承重量为j 的背包中的前i 个物品中最有价值子集的总价值。
可以把前i 个物品中能够放进承重量为j 的背包中的子集分成两个类别:包括第i 个物品的子集和不包括第i 个物品的子集。
1. 根据定义,在不包括第i 个物品的子集中,最优子集的价值是V[i-1,j]。
2. 在包括第i 个物品的子集中(因此,j-wi>=0),最优子集是由该物品和前i-1个物品中能够放进承重量为j-wi 的背包的最优子集组成。
这种最优子集的总价值等于vi+V[i-1,j-wi]。
因此,在前i 个物品中最优解得总价值等于这两个价值中的最大值。
当然,如果第i 个物品不能放进背包,从前i 个物品中选出的最优子集的总价值等于从前i-1个物品中选出的最优子集的总价值。
这个结果导致了下面的这个递推关系式:
初始条件:
当i,j>0时,V为了计算第i行第j列的单元格[i,j],我们拿前一行同一列的单元格与vi加上前一行左边wi列的单元格的和做比较,计算出两者的较大值。
相关代码;
void knapsack(int v[], int w[], int** m, int c, int n) //求最优值
{
intjmax = min(w[n]-1, c);
for (int j = 0; j <= jmax; j++)
m[n][j] = 0;
for (intjj = w[n]; jj<= c; jj++)
m[n][jj] = 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(intjj = w[i]; jj<= c; jj++)
m[i][jj] = max(m[i+1][jj], m[i+1][jj-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]);
cout<<endl<< "最优值:" << m[1][c] <<endl;
cout<<endl;
cout<<endl;
}
inttraceback(int x[], int w[], int** m, int c, int n) //求最优解{
cout<<endl<<"得到的一组最优解如下: "<<endl;
for(int i = 1; i < n; i++)
{
if(m[i][c] == m[i+1][c]) x[i] = 0;
else
{
x[i] = 1;
c -= w[i];
}
}
x[n] = (m[n][c]) ? 1:0;
for(int y = 1; y <= n; y++)
cout<< x[y] << "\t";
cout<<endl;
return x[n];
}
用课本上的一个例子进行测试:
预期结果应该是物品1,2和4。
价值为37美元。
背包问题中,对于一个物品,只有放入背包和不放入背包两种状态,用0表示物品不放入背包,用1表示放入背包。
上图的结果显示最优值为37,物品一、二、四放入包中,与预期结果相同。
随机产生n个物品的重量与价值,求解该实例的最优解。
产生随机数的代码如下:
调用以上两个方法求解
对n=20,w=20
做测试
V[i]和w[i]都是随机产生的,正确地得到了结果。
注:
(1)为了保证不使用特殊数字,采用随机生成数组的方法。
for(int i=0;i<n;i++)
{
a[i]=rand()%10;
b[i]=rand()%10;
}
为了保证每次得到的数字不同,必须使用种子,给不同的初始值
srand((unsigned)time(NULL));
(2)用取系统时间的方法,来获取该算法的时间。
由于time只能取到毫秒级别,当算法的时间太小时,用多次执行算法的方法来获取算法执行时间
time_t time1,time2;
time1=time(NULL);
for(i=0;i<100;i++)
////////////////////////////
time2=time(NULL);
cout<<(time2-time1)/100<<endl;
三.实验分析
分别针对以下情况求解:
(先展示结果,时间太短,运行时间显示为零,稍后再做处理)第一组:(n=10,W=10),(n=10,W=20),(n=10,W=30)
第二组:(n=20,W=10),(n=20,W=20),(n=20,W=30)
第三组:(n=30,W=10),(n=30,W=20),(n=30,W=30)
用取系统时间的方法,来获取该算法的时间。
由于time只能取到毫秒级别,当算法的时间太小时,用多次执行算法的方法来获取算法执行时间
time_t time1,time2;
time1=time(NULL);
for(i=0;i<1000000;i++)
////////////////////////////
time2=time(NULL);
cout<<(time2-time1)/100000<<endl;
如图所示,统计的时间为运行1000000次数后的时间
以上统计的时间为运行1000000次数后的时间
三组实验的时间效率的折线图,其中x轴是W的值,y轴是所花费的时间,用不同的颜色表示不同n所花费的时间。
结论:
可以发现n的规模越大,所花费的时间越多。
当n固定时,花费时间随着w的增大而增大。
但n的影响力是最大的。
因为动态规划将复杂的多阶段决策问题分解为一系列简单的、离散的单阶段决策问题, 采用顺序求解方法, 通过解一系列小问题达到求解整个问题目的。
所以分解的小问题的规模,直接决定了算法的效率。
四.实验心得
本次实验虽然花费很大的心思,但确实让我动态规划的认识更加深刻。
动态规划没有准确的数学表达式和定义精确的算法,它强调具体问题具体分析。
这次实验结束后让我感觉到好的算法是多么的重要,当然合理利用算法也是不可忽视的。
这次实验虽然花了很大精力,却收获累累。
注:1、报告内的项目或内容设置,可根据实际情况加以调整和补充。
2、教师批改学生实验报告时间应在学生提交实验报告时间后10日内。