算法设计与分析课程设计报告Word格式文档下载.docx
- 文档编号:22204023
- 上传时间:2023-02-03
- 格式:DOCX
- 页数:18
- 大小:157.21KB
算法设计与分析课程设计报告Word格式文档下载.docx
《算法设计与分析课程设计报告Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《算法设计与分析课程设计报告Word格式文档下载.docx(18页珍藏版)》请在冰豆网上搜索。
=M(其中,wk为第k件物品的容量,M为背包的容量)(此即约束条件)
然后我们再寻找限界函数,这个问题比较麻烦,我们可以回忆一下背包问题的贪心算法,即物品按照物品的价值/物品的体积来从大到小排列,然后最优解为(1,1,1.......,1,t,0,0,......),其中0<
=t<
=1;
因此,我们在确定第k个物品到底要不要放入的时候(在前k-1个物品已经确定的情况下),我们可以考虑我们能够达到的最大的价值,即我们可以通过计算只放入一部分的k物品来计算最大的价值。
我们要确保当前选择的路径的最大的价值要大于我们已经选择的路径的价值。
这就是该问题的限界条件。
通过该条件,可以减去很多的枝条,大大节省运行时间。
每次都对分割后的四个小块进行判断,判断特殊格是否在里面。
这里的判断的法是每次先记录下整个大块的左上角格的行列坐标,然后再与特殊格坐标进行比较,就可以知道特殊格是否在该块中。
如果特殊块在里面,这直接递归下去求即可,如果不在,这根据分割的四个块的不同位置,把右下角、左下角、右上角或者左上角的格标记为特殊块,然后继续递归。
在递归函数里,还要有一个变量s来记录边的格数,每次对块进行划分时,边的格数都会减半,这个变量是为了便判断特殊格的位置。
其次还要有一个变nCount来记录L型骨牌的数量。
三、建立数学模型
普通背包问题的数学描述为:
在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1≤i≤n。
C>
0,wi>
0,vi>
0,1≤i≤n,要求找出一个n元0-1向量(x1,x2,x3,·
,xn),xi∈{0,1},1≤i≤n,使得
≤C,而且
达到最大。
0-1背包问题的数学描述为:
不能将物品装入背包多次,也不能只装入部分的物品i。
C>
当k>
0时,将2k×
2k棋盘分割为4个2^k-1×
2^k-1子棋盘(a)所示。
特殊格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊格。
为了将这3个无特殊格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如(b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。
递归地使用这种分割,直至棋盘简化为棋盘1×
1。
四、算法设计
因为每一个物品都可以分割成单位块,单位块的利益越大显然总收益越大,所以它局部最优满足全局最优,可以用贪心法解决。
算法设计:
首先计算每种物品单位重量的价值Vi/Wi,然后按单位重量价值从大到小进行排序,根据贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。
或将这种物品全部装入背包后,背包的物品总重量未超过背包容量C,则选择单位重量价值次高的物品并尽可能多地装入背包,依此策略一直进行下去,直到背包装满为止。
该0-1背包问题采用的是回溯算法,回溯算法的基本解题步骤是:
(1)针对所给问题定义问题的解空间;
(2)确定易于搜索的解空间结构;
(3)以深度优先式搜索解空间,并在搜索过程中用剪枝函数避免无效的搜索。
a.物品有n种,背包容量为C,分别用p[i]和w[i]存储第i种物品的价值和重量,用
x[i]标记第i种物品是否装入背包,用bestx[i]存储第i种物品的最优装载案;
b.用递归函数Backtrack(i,cp,cw)来实现回溯法搜索子集树(形式参数i表示递归深
度,n用来控制递归深度,形式参数cp和cw表示当前总价值和总重量,bestp表示当前
最优总价值):
①若i>
n,则算法搜索到一个叶结点,判断当前总价值是否最优:
1>
若cp>
bestp,更新当前最优总价值为当前总价值(即bestp=cp),更新
装载案(即bestx[i]=x[i](1≤i≤n));
②采用for循环对物品i装与不装两种情况进行讨论(0≤j≤1):
x[i]=j;
2>
若总重量不大于背包容量(即cw+x[i]*w[i]<
=c),则更新当前总价br="
"
>
值和总重量(即cw+=w[i]*x[i],cp+=p[i]*x[i]),对物品i+1调用递归函
数Backtrack(i+1,cp,cw)继续进行装载;
3>
函数Backtrack(i+1,cp,cw)调用结束后则返回当前总价值和总重量
(即cw-=w[i]*x[i],cp-=p[i]*x[i]);
4>
当j>
1时,for循环结束;
③当i=1时,若已测试完所有装载案,外层调用就全部结束;
c.主函数调用一次backtrack(1,0,0)即可完成整个回溯搜索过程,最终得到的bestp和bestx[i]即为所求最大总价值和最优装载案。
该棋盘算法用的是分治算法,分治法解题的思路就是将大问题化为若干子问题,再依次解决子问题,最后获得问题的答案。
(1)ChessBoard函数实现了递归的将棋盘划分为子棋盘,并将棋盘进行覆盖。
(2)main()函数用来进行输入棋盘的大小和特殊棋盘的位置。
(3)使用memset(Matrix,0,sizeof(Matrix))将Matrix[]数组清零。
五、算法实现
#include<
stdio.h>
structgoodinfo
{
floatp;
//物品价值
floatw;
//物品重量
floatx;
//物品该放数量
intflag;
//物品编码
};
voidInsertionsort(goodinfogoods[],intn)
inti,j;
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;
for(i=1;
i<
i++)
goods[i].x=0;
cu=M;
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;
while(goods[0].flag<
goods[i].flag)
printf("
最优解为:
\n"
);
printf("
第%d件物品要放:
%f"
goods[i].flag,goods[i].x);
voidmain()
-----------运用贪心算法求解普通背包问题-------------\n"
intj,n;
floatM;
goodinfo*goods;
while(j)
请输入物品的总数量:
"
scanf("
%d"
&
n);
goods=newstructgoodinfo[n+1];
请输入背包的最大容量:
%f"
M);
for(inti=1;
goods[i].flag=i;
printf("
请输入第%d个物品的重量:
i);
scanf("
goods[i].w);
请输入第%d个物品的价值:
goods[i].p);
goods[i].p=goods[i].p/goods[i].w;
Insertionsort(goods,n);
bag(goods,M,n);
如果继续则选择“1”,如果结束则选择“0”\n"
j);
#include<
intn,c,bestp;
//物品的个数,背包的容量,最大价值
intp[10000],w[10000],x[10000],bestx[10000];
//物品的价值,物品的重量,x[i]暂存物品的选中情况,物品的选中情况
voidBacktrack(inti,intcp,intcw)
{//cw当前包物品重量,cp当前包物品价值
intj;
if(i>
n)//回溯结束
if(cp>
bestp)
bestp=cp;
for(i=0;
i++)bestx[i]=x[i];
else
for(j=0;
=1;
j++)
x[i]=j;
if(cw+x[i]*w[i]<
=c)
cw+=w[i]*x[i];
cp+=p[i]*x[i];
Backtrack(i+1,cp,cw);
cw-=w[i]*x[i];
cp-=p[i]*x[i];
intmain()
inti;
bestp=0;
请输入背包最大容量:
scanf("
c);
请输入物品个数:
请依次输入物品的重量:
i++)
w[i]);
请依次输入物品的价值:
p[i]);
Backtrack(1,0,0);
最大价值为:
%d\n"
bestp);
被选中的物品依次是(0表示未选中,1表示选中)\n"
%d"
bestx[i]);
return0;
string.h>
intnCount=0;
intMatrix[100][100];
voidchessBoard(inttr,inttc,intdr,intdc,intsize);
注意:
矩阵大小为2的k次!
inty=1;
while(y)
intsize,r,c,row,col;
memset(Matrix,0,sizeof(Matrix));
请输入矩阵的大小:
size);
请输入特殊矩阵的坐标:
%d%d"
row,&
col);
chessBoard(0,0,row,col,size);
for(r=0;
r<
size;
r++)
for(c=0;
c<
c++)
{
printf("
%2d"
Matrix[r][c]);
}
如果继续则按“1”,退出则按“0”:
y);
voidchessBoard(inttr,inttc,intdr,intdc,intsize)
//覆盖左上角子棋盘
ints,t;
if(1==size)return;
s=size/2;
//分割棋盘
t=++nCount;
//L型骨牌号
//特殊格在此棋盘中
if(dr<
tr+s&
&
dc<
tc+s)
chessBoard(tr,tc,dr,dc,s);
else
Matrix[tr+s-1][tc+s-1]=t;
chessBoard(tr,tc,tr+s-1,tc+s-1,s);
//locatethespecialgridonbottomleftcorner
dc>
=tc+s)
chessBoard(tr,tc+s,dr,dc,s);
Matrix[tr+s-1][tc+s]=t;
chessBoard(tr,tc+s,tr+s-1,tc+s,s);
//locatethespecialgridontoprightcorner
if(dr>
=tr+s&
tc+s)
chessBoard(tr+s,tc,dr,dc,s);
}
Matrix[tr+s][tc+s-1]=t;
chessBoard(tr+s,tc,tr+s,tc+s-1,s);
//locatethespecialgridontopleftcorner
=tc+s)
chessBoard(tr+s,tc+s,dr,dc,s);
Matrix[tr+s][tc+s]=t;
chessBoard(tr+s,tc+s,tr+s,tc+s,s);
}六、测试分析
(1)输出结果
(2)复杂度分析
时间复杂度为O(nlgn)
(3)问题及解决
计算上界需要O(n)时间,在最坏的情况下有O(pow(2,n))个右儿子结点需要计算上界所以0-1背包问题的回溯算法所需的计算时间为O(*npow(2,n))。
设T(n)是算法ChessBoard覆盖一个2^k*2^k棋盘所需要的时间,则从算法的分治策略可知,T(k)满足如下递归程:
T(k)=
k=0
k>
0解得此递归程可得T(k)=O(4^k)。
由于覆盖一个2^k*2^k棋盘所需的L型骨牌个数为(4^k—1)/3,故算法ChessBoard是一个在渐进意义下最优的算法
七、结论
普通背包问题采用的是贪心算法。
0-1背包问题采用的是回溯算法
棋盘覆盖问题采用的是分治算法
总结所解决的问题(采用的什么算法,怎么设计的,还存在哪些问题有待改进等容)。
八、参考文献(6个)
参考文献要注明作者、出版社、出版日期。
如
[1]申俊龙著.新编医院管理教程[M].北京:
科学出版社,2005:
25-163.
[2]BrianHenderson-Sellers.ABookofObject-OrientedKnowledge:
AnIntroductiontoObject-OrientedSoftwareEngineering[M].Prentice-Hall,1993:
39-113
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 设计 分析 课程设计 报告