河北工业大学算法分析实验报告.docx
《河北工业大学算法分析实验报告.docx》由会员分享,可在线阅读,更多相关《河北工业大学算法分析实验报告.docx(10页珍藏版)》请在冰豆网上搜索。
河北工业大学算法分析实验报告
算法设计与分析
实验报告
一、实验目的与要求:
熟悉C/C++语言的集成开发环境;
通过本实验加深对贪心算法、动态规划和回溯算法的理解。
二、实验内容:
掌握贪心算法、动态规划和回溯算法的概念和基本思想,分析并掌握"0-1"背包问题的三种算法,并分析其优缺点。
三、实验题:
1."0-1"背包问题的贪心算法
2."0-1"背包问题的动态规划算法
3."0-1"背包问题的回溯算法
四、实验步骤:
1.理解算法思想和问题要求;
2.编程实现题目要求;
3.上机输入和调试自己所编的程序;
4.验证分析实验结果;
5.整理出实验报告。
五、实验程序:
1、“0-1”背包问题的贪心算法源程序
#include
structgoodinfo
{
floatp;//物品效益
floatw;//物品重量
floatX;//物品该放的数量
intflag;//物品编号
};//物品信息结构体
voidInsertionsort(goodinfogoods[],intn)
{
intj,i;
for(j=2;j<=n;j++)
{
goods[0]=goods[j];
i=j-1;
while(goods[0].p>goods[i].p)
{
goods[i+1]=goods[i];
i--;
}
goods[i+1]=goods[0];
}
}//按物品效益,重量比值做升序排列
voidbag(goodinfogoods[],floatM,intn)
{
floatcu;
inti,j;
for(i=1;i<=n;i++)
goods[i].X=0;
cu=M;//背包剩余容量
for(i=1;i{
if(goods[i].w>cu)//当该物品重量大与剩余容量跳出
break;
goods[i].X=1;
cu=cu-goods[i].w;//确定背包新的剩余容量
}
if(i<=n)
goods[i].X=cu/goods[i].w;//该物品所要放的量
/*按物品编号做降序排列*/
for(j=2;j<=n;j++)
{
goods[0]=goods[j];
i=j-1;
while(goods[0].flag{
goods[i+1]=goods[i];
i--;
}
goods[i+1]=goods[0];
}
cout<<"最优解为:
"<for(i=1;i<=n;i++)
{
cout<<"第"<
";
cout<}
}
voidmain()
{
cout<<"|--------运用贪心法解背包问题---------|"<cout<<"|-------------------------------------|"<intj;
intn;
floatM;
goodinfo*goods;//定义一个指针
while(j)
{
cout<<"请输入物品的总数量:
";
cin>>n;
goods=newstructgoodinfo[n+1];//
cout<<"请输入背包的最大容量:
";
cin>>M;
cout<inti;
for(i=1;i<=n;i++)
{goods[i].flag=i;
cout<<"请输入第"<
";
cin>>goods[i].w;
cout<<"请输入第"<
";
cin>>goods[i].p;
goods[i].p=goods[i].p/goods[i].w;//得出物品的效益,重量比
cout<}
Insertionsort(goods,n);
bag(goods,M,n);
cout<<"press<1>torunagian"<cout<<"press<0>toexit"<cin>>j;
}
}
2、“0-1”背包问题动态规划算法远程序:
#include
#defineMAX20
intn,c,w[MAX],v[MAX],m[MAX][MAX]={0};
voidknapsack()
{inti,j;
for(i=1;i<=n;i++)
for(j=1;j<=c;j++)
{m[i][j]=m[i-1][j];
if(j>=w[i-1]&&m[i-1][j-w[i-1]]+v[i-1]>m[i][j])
m[i][j]=m[i-1][j-w[i-1]]+v[i-1];
}
}
//显示所取的物品及其重量(其中一个解)
//对数组m的最后一列检查来求解
voiddisp()
{inti,j;
i=n;
while(m[i][c]==m[i-1][c])i--;
while(i>0)
{j=i-1;
while(m[i][c]-m[j][c]!
=v[i-1]&&j>0)
j--;
printf("%5d%5d\n",w[i-1],v[i-1]);
i=j;
}
}
voidmain()
{inti,j;
printf("输入物品种数:
");scanf("%d",&n);
printf("输入每种物品的重量与价值:
\n");
for(i=0;iscanf("%d%d",&w[i],&v[i]);
printf("输入背包的总重量:
\n");scanf("%d",&c);
knapsack();disp();
printf("最大价值=%d\n",m[n][c]);
for(i=0;i<=n;i++)
{for(j=0;j<=c;j++)
printf("%3d",m[i][j]);
printf("\n");}
}
3、"0-1"背包问题的回溯算法源程序:
#include
usingnamespacestd;
voidinput(int*number,int*weight,int*price){
inti,n;
cout<<"包的容量:
";
cin>>weight[0];
cout<<"物品数:
";
cin>>*number;
cout<<"各物品的重量:
";
for(i=1;i<=*number;i++){
cin>>weight[i];
}
cout<<"各物品的价值:
";
for(i=1;i<=*number;i++){
cin>>price[i];
}
}
voidbacktrack(intt,intn,int*weight,int*price,int*maxPrice,int*flag,int*nowWeight,int*nowPrice,int*x){
inti;
if(t>n){
if(*nowWeight<=weight[0]&&*nowPrice>*maxPrice){
*maxPrice=*nowPrice;
flag[0]=0;
for(i=1;i<=n;i++){
if(x[i]){
flag[++flag[0]]=i;
}
}
}
return;
}else{
for(i=0;i<=1;i++){
x[t]=i;
*nowWeight+=weight[t]*i;
*nowPrice+=price[t]*i;
backtrack(t+1,n,weight,price,maxPrice,flag,nowWeight,nowPrice,x);
*nowWeight-=weight[t]*i;
*nowPrice-=price[t]*i;
}
}
}
voidoutput(int*maxPrice,int*flag){
inti;
cout<cout<<"物品的最大价值为:
"<<*maxPrice<cout<<"选中的物品为:
";
for(i=1;i<=flag[0];i++){
cout<}
cout<}
intmain(){
inttemp1=0,temp2=-1,temp3=0,temp4=0;//这一行很重要!
int*number=&temp1,weight[100],price[100];
int*maxPrice=&temp2,flag[100],*nowWeight=&temp3,*nowPrice=&temp4,x[100];
input(number,weight,price);
backtrack(1,*number,weight,price,maxPrice,flag,nowWeight,nowPrice,x);
output(maxPrice,flag);
return0;
}
六、实验结果:
1、贪心算法实验结果:
2、动态规划法实验结果:
3、回溯算法实验结果:
七、实验分析:
1、“0-1”背包问题的贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。
在本问题中,通过求出每件物品的单位效益来确定放入哪个物品,从而求出解。
本题目第一件物品的单位效益为6,而第二件物品的单位效益为2,第三件物品的单位效益为4,按照升序排列,顺序为:
132,有因为背包容量为2,所以,重量为1的第一件物品可以放入。
由于第三件物品的重量为2,所以只能放入一半,背包的容量就满了,不能再放了。
2、“0-1”背包问题的动态规划算法
动态规划过程是:
每次决策依赖于当前状态,又随即引起状态的转移。
一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。
在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。
依次解决各子问题,最后一个子问题就是初始问题的解。
本题目中m[i][j]表示有i个物品,背包容量为j时的最优解,通过knapsack函数用来寻找最优解的值,自底向上地对每一个物品进行运算,都将把其放入与不放入背包两种情况下背包的总价值作=进行比较,然后选择中值较大者作为当前状态下的最优值,最后求出最优值。
在通过disp函数用来输出动态规划法中的二维矩阵。
3、“0-1”背包问题的回溯算法
回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。
但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
一般步骤为:
(1)针对所给问题,定义问题的解空间;
(2)确定易于搜索的解空间结构;(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
本题目采用的是定长的解空间,从根结点出发,以深度优先方式搜索整个解空间。
Backtrack函数用来进行深度搜索,程序用了指针的方法对左右子树进行搜索,当进入左子树的条件不满足时,就对其进行右子树搜索,如果还是不满足,就进行回溯。
每次到达叶子结点时都是更新最优值,故最后求出来的解一定是最优解。