算法分析论文.docx
《算法分析论文.docx》由会员分享,可在线阅读,更多相关《算法分析论文.docx(15页珍藏版)》请在冰豆网上搜索。
![算法分析论文.docx](https://file1.bdocx.com/fileroot1/2023-1/31/b63a8f0c-1564-422e-9d9c-f2f13a92effa/b63a8f0c-1564-422e-9d9c-f2f13a92effa1.gif)
算法分析论文
成绩评定表
学生姓名
班级学号
专业
信息与计算科学
课程设计题目
1.动态规划0-1背包问题2.分支限界法求解0-1背包问题
评
语
组长签字:
成绩
日期
20年月日
课程设计任务书
学院
理学院
专业
信息与计算科学
学生姓名
班级学号
课程设计题目
1.动态规划0-1背包问题2.分支限界法求解0-1背包问题
实践教学要求与任务:
1、巩固和加深对计算机算法分析与设计基本知识的理解。
2、初步掌握简单软件的分析方法和设计方法。
3、了解与课程有关的工程技术规范,能正确解释和分析设计结果。
4、具体任务
(1)动态规划解决0-1背包问题
(2)分支限界法求解0-1背包问题
工作计划与进度安排:
第一天查阅资相关料;第二、三天程序设计;
第四天程序调试;第五天答辩
指导教师:
201年月日
专业负责人:
201年月日
学院教学副院长:
201年月日
摘要
以最低的成本、最快的速度、最优的质量开发软件工程师追求的目标。
而要设计这种软件,不但要遵循软件工程的原则,而且还需要合理的数据组织和高效、简洁的算法。
在软件设计的各个领域,算法都扮演着重要角色,被公认为是计算机科学的灵魂。
没有算法,计算机程序将不复存在。
学会读懂算法、设计算法、实现算法是软件开发中的最基本要求,而发明算法并证明该算法的正确性则是软件设计的最高境界。
在理解算法的基础上最终实现算法是算法分析的目标,通过对计算机算法系统的学习与研究,理解和掌握算法设计的主要方法,培养对算法的计算复杂性进行正确分析的能力,从而为独立设计算法并对算法的复杂性分析奠定坚实的基础。
因此,无论是否涉及计算机,特定的算法设计技术都可以看成是问题求解的有效策略。
动态规划和分支限界方法是算法分析中很重要的算法,在求解0-1背包问题时,是很好的算法,利用动态规划算法,可以从容而高效地解决很多贪心算法或分治算法不能解决的问题,而分支限界法是在解空间中搜索问题的可行解或最优解,但搜索的方式是采用宽度优先的方式搜索解空间树,这两种方法是很好的求解问题的方法
关键词:
0-1背包;算法分析;动态规划;分支限界法
目录
1动态规划解0-1背包问题1
1.1问题重述1
1.2问题分析1
1.3算法分析与设计1
1.32算法设计3
1.4算法的实现与结果3
2分支限界法求解0-1背包问题5
2.1问题重述5
2.2问题分析6
2.3算法分析与设计6
2.31算法分析6
2.32算法设计7
2.4算法实现与结果7
总结14
参考文献15
1动态规划解0-1背包问题
1.1问题重述
0-1背包问题:
一个旅行者有一个最多能装C公斤重量的背包,已知n个重量和价值分别为w[i]>0和p[i]>0(i=1,2,…,n)的物品,选择哪些物品装入背包,可使在背包的容量限制之内所装物品的价值最大,这就是背包问题。
0-1背包特点是:
每种物品都仅有一件,可以选择放入或不放。
0-1背包问题:
给定n种物品和一个背包。
物品i的重量是Wi,其价值为Vi,背包的容量为C。
应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包为1或不装入背包为0。
不能将物品i装入背包多次,也不能只装入部分的物品i。
021背包问题的主要特点是在选择物品i装入背包时,每种物品仅有一件,可以选择放或不放。
1.2问题分析
1.对于n个物品进行简单的排序,用贪心算法求出其初始可行解,将初始可行解设为当前最优解;
2.确定剪枝原则:
在每次装入一个物品前,判断当前要装入的物品的质量是否能装入背包;在每一次装入一个物品后将当前值与剩余未决策的物品的上界求和,判断是否大于当前最优值,若大于最优值,剪去该分支。
3.在一个分支结束时的可行解与当前最优解比较,若小于当前最优解,则更新最优解。
1.3算法分析与设计
1.31算法分析
动态规划算法的基本思想是把原问题分解成一系列子问题,然后从这些子问题中求出原问题的解。
对一个负重能力为m的背包,如果选择装入一个第i种物品,那么原背包问题就转化为负重能力为m2w的子背包问题。
由于动态规划算法求解过程中反复出现子问题,且对每次重复出现的子问题都要重新解一次,这需要多花费不少时间,因此动态规划算法的时间复杂度为O(n*m),其中n为物体的个数,m为背包负重。
动态规划是用空间换时间的一种方法的抽象。
其关键是发现子问题和记录其结果。
然后利用这些结果减轻运算量。
因为背包的最终最大容量未知,所以,我们得从1到M一个一个的试,比如,刚开始任选N件物品中的一个,看对应的M的背包,能不能放进去,如果能放进去,并且还有多少空间,则,多出来的空间能放N-1物品中的最大价值,怎么能保证总选则是最大价值呢,看下表:
测试数据:
10,3
3,4
4,5
5,6
最大容量M
物品个数N
j=0-m
10
3
C
0
1
2
3
4
5
6
7
8
9
物品大小W
物品价值p
编号
0
0
0
0
0
0
0
0
0
3
4
i=1
1
0
0
0
4
4
4
4
4
4
4
4
5
1-n2
2
0
0
0
4
5
5
5
9
9
9
5
6
3
3
0
0
0
4
5
6
6
9
10
11
c[i][j]数组保存了1,2,3号物品依次选择后的最大价值。
这个最大价值是怎么得来的呢?
从背包容量为0开始,1号物品先试,0,1,2,的容量都不能放.所以置0,背包容量为3则里面放4.这样,这一排背包容量为4,5,6,....10的时候,最佳方案都是放4.假如1号物品放入背包.则再看2号物品.当背包容量为3的时候,最佳方案还是上一排的最价方案c为4.而背包容量为5的时候,则最佳方案为自己的重量5.背包容量为7的时候,很显然是5加上一个值了。
加谁?
?
很显然是7-4=3的时候.上一排c3的最佳方案是4.所以。
总的最佳方案是5+4为9.这样.一排一排推下去。
最右下放的数据就是最大的价值了。
(注意第3排的背包容量为7的时候,最佳方案不是本身的6.而是上一排的9.说明这时候3号物品没有被选.选的是1,2号物品.所以得9。
从以上最大价值的构造过程中可以看出。
f(n,m)=max{f(n-1,m),f(n-1,m-w[n])+P(n,m)}这就是书本上写的动态规划方程。
1.32算法设计
设m[i][j]用来表示从前i项物品中区取出装入体积为j的背包的物品的最大价值。
其中i的范围为1到n,其中j的范围为0到c,程序要寻求的解为m[n][c]。
可以清楚地发现:
1m[0][j]对所有的j的值为0,m[i][0]对所有的i的值为0。
2当前的体积j大于等于w[i]时,m[i][j]是下面两个量的最大值:
m[i-1][j]和m[i-1][j-w[i]]+v[i]
3当前的体积j小于w[i]时,m[i][j]等于m[i-1][j]
m[i][j]=
1.4算法的实现与结果
代码:
#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];
}
}
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");}
}
运行结果与分析:
图1.4运行结果
根据运行的所得的结果:
当总重量为9,物品1:
5、4物品2:
3、4物品3:
2、3物品4:
1、1的时候,最优解为9,放第1、2、4个物品。
2分支限界法求解0-1背包问题
2.1问题重述
若-1背包问题:
一个旅行者有一个最多能装C公斤重量的背包,已知n个重量和价值分别为w[i]>0和p[i]>0(i=1,2,…,n)的物品,选择哪些物品装入背包,可使在背包的容量限制之内所装物品的价值最大,这就是背包问题。
0-1背包特点是:
每种物品都仅有一件,可以选择放入或不放。
0-1背包问题:
给定n种物品和一个背包。
物品i的重量是Wi,其价值为Vi,背包的容量为C。
应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
在选择装入背包的物品时,对每种物品i只有两种选择,即装入背包为1或不装入背包为0。
不能将物品i装入背包多次,也不能只装入部分的物品i。
021背包问题的主要特点是在选择物品i装入背包时,每种物品仅有一件,可以选择放或不放。
2.2问题分析
1.对于n个物品进行简单的排序,用贪心算法求出其初始可行解,将初始可行解设为当前最优解;
2.确定剪枝原则:
在每次装入一个物品前,判断当前要装入的物品的质量是否能装入背包;在每一次装入一个物品后将当前值与剩余未决策的物品的上界求和,判断是否大于当前最优值,若大于最优值,剪去该分支。
3.在一个分支结束时的可行解与当前最优解比较,若小于当前最优解,则更新最优解。
2.3算法分析与设计
2.31算法分析
分支限界(branchandbound)搜索法是一种在问题的解空间树上搜索问题的解的方法。
但与回溯算法不同,分支定界算法采用广度优先或最小耗费优先的方法搜索解空间树,并且,在分支定界算法中,每一个活结点只有一次机会成为扩展结点。
分支定界法的思想是:
首先确定目标值的上下界,边搜索边减掉搜索树的某些支,提高搜索效率。
解题步骤:
(1)在问题的边带权的解空间树中进行广度优先搜索
(2)找一个叶结点使其对应路径的权最小(最大)
(3)当搜索到达一个扩展结点时,一次性扩展它的所有儿子
(4)将满足约束条件且最小耗费函数目标函数限界的儿子,插入活结点表中
(5)从活结点表中取下一结点同样扩展
(6)直到找到所需的解或活动结点表为空为止
在解0-1背包问题的优先队列式分支限界法中,活结点优先队列中结点元素N的优先级由该结点的上界函数Bound计算出的值uprofit给出。
子集树中以结点N为根的子树中任一结点的价值不超过N.profit。
可用一个最大堆来实现活结点优先队列。
堆中元素类型为HeapNode,其私有成员有uprofit,profit,weight和level。
对于任意活结点N,N.weight是结点N所相应的重量;N.profit是N所相应的价值;N.uprofit是结点N的价值上界,最大堆以这个值作为优先级。
子集空间树中结点类型为bbnode。
2.32算法设计
给定n种物品和一个容量为C的背包,物品i的重量是Wi,其价值为Vi,0/1背包问题是如何选择装入背包的物品(物品不可分割),使得装入背包中物品的总价值最大,一般情况下,解空间树中第i层的每个结点,都代表了对物品1~i做出的某种特定选择,这个特定选择由从根结点到该结点的路径唯一确定:
左分支表示装入物品,右分支表示不装入物品。
对于第i层的某个结点,假设背包中已装入物品的重量是w,获得的价值是v,计算该结点的目标函数上界的一个简单方法是把已经装入背包中的物品取得的价值v,加上背包剩余容量W-w与剩下物品的最大单位重量价值vi+1/wi+1的积,于是,得到限界函数:
ub=v+(W-w)×(vi+1/wi+1)
根据限界函数确定目标函数的界[down,up],然后,按照广度优先策略遍历问题的空间树。
2.4算法实现与结果
代码如下:
#include
#include
#defineMaxSize100//最多结点数
typedefstructQNode
{
floatweight;
floatvalue;
intceng;
structQNode*parent;
boolleftChild;
}QNode,*qnode;//存放每个结点
typedefstruct
{
qnodeQ[MaxSize];
intfront,rear;
}SqQueue;//存放结点的队列
SqQueuesq;
floatbestv=0;//最优解
intn=0;//实际物品数
floatw[MaxSize];//物品的重量
floatv[MaxSize];//物品的价值
intbestx[MaxSize];//存放最优解
qnodebestE;
voidInitQueue(SqQueue&sq)//队列初始化
{
sq.front=1;
sq.rear=1;
}
boolQueueEmpty(SqQueuesq)//队列是否为空
{
if(sq.front==sq.rear)
returntrue;
else
returnfalse;
}
voidEnQueue(SqQueue&sq,qnodeb)//入队
{
if(sq.front==(sq.rear+1)%MaxSize)
{
printf("队列已满!
");
return;
}
sq.Q[sq.rear]=b;
sq.rear=(sq.rear+1)%MaxSize;
}
qnodeDeQueue(SqQueue&sq)//出队
{
qnodee;
if(sq.front==sq.rear)
{
printf("队列已空!
");
return0;
}
e=sq.Q[sq.front];
sq.front=(sq.front+1)%MaxSize;
returne;
}
voidEnQueue1(floatwt,floatvt,inti,QNode*parent,boolleftchild)
{
qnodeb;
if(i==n)//可行叶子结点
{
if(vt==bestv)
{
bestE=parent;
bestx[n]=(leftchild)?
1:
0;
}
return;
}
b=(qnode)malloc(sizeof(QNode));//非叶子结点
b->weight=wt;
b->value=vt;
b->ceng=i;
b->parent=parent;
b->leftChild=leftchild;
EnQueue(sq,b);
}
voidmaxLoading(floatw[],floatv[],intc)
{
floatwt=0;
floatvt=0;
inti=1;//当前的扩展结点所在的层
floatew=0;//扩展节点所相应的当前载重量
floatev=0;//扩展结点所相应的价值
qnodee=NULL;
qnodet=NULL;
InitQueue(sq);
EnQueue(sq,t);//空标志进队列
while(!
QueueEmpty(sq))
{
wt=ew+w[i];
vt=ev+v[i];
if(wt<=c)
{
if(vt>bestv)
bestv=vt;
EnQueue1(wt,vt,i,e,true);//左儿子结点进队列
}
EnQueue1(ew,ev,i,e,false);//右儿子总是可行;
e=DeQueue(sq);//取下一扩展结点
if(e==NULL)
{
if(QueueEmpty(sq))break;
EnQueue(sq,NULL);//同层结点尾部标志
e=DeQueue(sq);//取下一扩展结点
i++;
}
ew=e->weight;//更新当前扩展结点的值
ev=e->value;
}
printf("最优取法为:
\n");
for(intj=n-1;j>0;j--)//构造最优解
{
bestx[j]=(bestE->leftChild?
1:
0);
bestE=bestE->parent;
}
for(intk=1;k<=n;k++)
{
if(bestx[k]==1)
printf("\n物品%d:
重量:
%.1f,价值:
%.1f\n",k,w[k],v[k]);
}
printf("\n");
printf("最优价值为:
%.1f\n\n",bestv);
}
intmain()
{
intc;
floatewv[MaxSize];
printf("////////////////////0-1背包问题分枝限界法/////////////////////\n\n");
printf("请输入物品的数量:
\n");
scanf("%d",&n);
printf("请输入背包的最大承重量:
\n");
scanf("%d",&c);
printf("\n请输入物品的重量和单位重量价值:
\n\n");
for(inti=1;i<=n;i++)
{
printf("物品%d:
",i);
scanf("%f%f",&w[i],&ewv[i]);
v[i]=w[i]*ewv[i];
printf("\n");
}
maxLoading(w,v,c);
}
结果分析:
图2.4运行结果
通过代码和运行结果,我们能够看到,最有价值为33。
总结
在写论文的过程中,我上网查询了很多资料,并且也参考了书本里的内容,通过这些我对算法分析设计又有了进一步的了解,对算法的复杂度也有了新的认识。
对于我们常用的动态规划算法、回溯法、分支限界法、贪心算法等的思想有了进一步的了解,我相信这对我以后的学习是非常有用的。
虽然这门课程已经结束了,但是我所掌握的却很少,因此在接下来的时间里我还会继续学习算法分析与设计,从而能够运用这些算法解决更多的问题。
解决该问题首先要确定一个合适的限界函数数,并根据限界函数确定目标函数的界[down,up],然后按照广度优先策略遍历问题的解空间树,在分支结点上,依次搜索该结点的所有孩子结点,分别估算这些孩子结点的目标函数的可能取值,如果某孩子结点的目标函数可能取得的值超出目标函数的界,则将其丢弃,因为从这个结点生成的解不会比目前已经得到的解更好;否则,将其加入待处理结点表中。
依次选取使目标函数的值取得极值的结点成为当前扩展结点,重复上述过程,直到找到最优解。
参考文献
[1]龚雄兴,堆与贪心算法[M],湖北襄樊学院,2003.
[2]张洁,朱莉娟.贪心算法与动态规划的比较[M].新乡师范高等专科科学学报,
[3]殷建平.关于贪心算法的正确性证明[M].江西师范大学学报,1998.10.
[4]王晓东.计算机算法设计与分析(第3版)[M].北京:
电子工业出版社,2007.
[5]朱洪.算法设计和分析[M].上海科学技术文献出版社,1989,162-163.
[6]卢开澄.计算机算法导引—设计与分析[M].北京:
清华大学出版社,2003.