背包问题四种不同算法的实现

  • 格式:doc
  • 大小:142.50 KB
  • 文档页数:8

下载文档原格式

  / 8
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

2
重量价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物
品总量未超过 c,则选择单位重量价值次高的物品并尽可能多地装入背包。
依此策略一直进行下去,直到背包装满为止。
3、算法设计如下:
#include<>
#define
max
100
2n 2n D=i;
n max vk xk
k i
n
给定 n 种物品和 1 个背包。物品 i 的重量是 wi,其价值为 pi,背包 的容量为 M。问应如何装入背包中的物品,使得装人背包中物品的总价值最 大在选择装人背包的物品时,对每种物品 i 只有两种选择,即装入背包、 不装入背包。不能将物品 i 装人背包多次,也不能只装入部分的物品 i。 该问题称为 0-1 背包问题。
int
p[100],w[20],x[20];
while(1)
{
cout<<"0-1 背包问题
——递归法"<<endl;
cout<<" 请 输 入 背 包
的容量:"<<endl;
cout<<"请输入物品个数:
"<<endl;
cout<<" 请 输 入 物 品
的重量:"<<endl;
cout<<" 请 输 入 物 品
兰州交通大学
数理与软件工程学院
题 目 0-1 背包问题算法实现
院系 专业班级 学生姓名 学号 指导教师
数理院 信计 09 雷雪艳 0 李秦
二O一二年 六 月 五 日
1
一、问题描述: 1、0—1 背包问题:给定 n 种物品和一个背包,背包最大容量
为 M,物品 i 的重量是 wi,其价值是平 Pi,问应当如何选择装入背包的物品, 似的装入背包的物品的总价值最大
背包问题的数学描述如下: 2、要求找到一个 n 元向量(x1,x2…xn),在满足约束条件:
x p
xi wi M max
0 xi 1 情况下,使得目标函数
i i ,其中,1 i n;M>0;
wi>0;pi>0。满足约束条件的任何向量都是一个可行解,而使得目标函数 达到最大的那个可行解则为最优解[1]。
if(V[i][W]
==
[i]=w[Q[i-1].ID];
V[i+1][W])
}
=0;
=0;
=c;
3
=n; =0;
D=i;
Q[i-1].d=(float)*p[i]/w[i
];
P+=p[i];
W+=w[i];
}
if(W<=c)
return
P;<Q[j].d)
{
f=Q[i].d;
Q[i].d=Q[j].d; Q[j].d=f;
} } D]; [i]=w[Q[i-1].ID]; } =0; =0; =c; =n; 4、运行结果如下图所示:
D]=[j];
delete []Q;
delete [];
delete [];
delete [];
return bestp;
}
void main()
{
int m,n;
int i=0,j=0;
cout<<"背包的最优解为:"<<endl<<Knapsack(p,w,m,n,x)<<endl; cout<<"最优解条件下选择的背包为:"<<endl; for(i=1;i<=n;i++)
cout<<x[i]<<"\t"; cout<<endl; }
7
}
void jiemian() {
printf(" \n"); printf(" \n"); printf(" \n"); printf(" \n"); } //主函数 int main() { while(1) {
{ f=Q[i].d;
Q[i].d=Q[j].d;
n
w1y1 wi zi
n
max vk xk
i2
k i
Q[j].d=f; } }
n
wk xk j
k i
xk {0,1}, i k n
Knap K; = new int[n+1];
= new int[n+1]; = new int[n+1];
return P;<Q[j].d) {
f=Q[i].d; Q[i].d=Q[j].d; Q[j].d=f; } } Knap K; = new int[n+1];
= new int[n+1]; = new int[n+1]; = new int[n+1]; [0]=0; [0]=0; for( i=1;i<=n;i++) { [i]=p[Q[i-1].ID]; [i]=w[Q[i-1].ID]; } =0; =0; =c; =n; =0;
贪心算法总是作出在当前看来是最好的选择,即贪心算法并不从整 体最优解上加以考虑,它所作出的选择只是在某种意义上的局部最优解。贪 心算法不是对所有问题都能得到整体最优解,但对范围相当广的许多问题它 能产生整体最优解。在一些情况下,即使贪心算法不能得到整体最优解,但 其最终结果却是最优解的很好近似解。
贪心算法求解的问题一般具有两个重要性质:贪心选择性质和最优子结 构性质。所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部 最优解的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素, 也是贪心算法与动态规划算法的主要区别。当一个问题的最优解包含其子问 题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该 问题可用动态规划算法或贪心算法求解的关键特征。 2、0-1 背包问题的实现
建立动态 规划递归方程
回溯 法
O(n 2n )
能够获得 最优解
时间复杂 度较高
判断右子树 时,按效率密 度 vi/wi 对剩 余对象排序
5
分枝限界法
O( 2n )
贪心 算法
O(nlogn)
#include<> #include<iostream> #include<> #include<> #include<> #define max 100 Q[i-1].d=*p[i]/w[i]; P+=p[i]; W+=w[i]; } if(W<=c)
max{m(i 1), j),m(i 1, j wi) vi}, j = nweiw int[n+1];
m(i, j)
m(i 1, j),0 j wj
[0]=0; [0]=0;
vnj wn m(n, j) 0 j wn {
for( i=1;i<=n;i++) { [i]=p[Q[i-1].ID];
通过以上对 0-1 背包问题的求解分析,我们可以看到各种算法设计方法有各 内不同的特点,针对不同的问题领域,它们有不同的效率,对于求解 0-1 背包问 题,各算法的时间复杂度、优缺点以及改进方法的比较如下表所示:
算法
时间复杂度
优点
缺点
改进方法
动态
O(min{nc,
规划
2n })
可求得最 优决策序列
速度较慢
0-1 背包问题的符号化表示是,给定 M>0, w i >0, pi >0,1 i n , 要求找到一个 n 元 0-1 向量向量(x1,x2…xn), X i =0 或 1 , 1 i n, 使 得
x p xiwi M
,而且
i i 达到最大[2]。
二、解决方案: 方案一:贪心算法 1、贪心算法的基本原理与分析
速度较 快,易求解
可以达到 局部最优解, 用时少
占用的内 存较大,效率 不高
不能考虑 到整体最优 解,程序可读 性低于动态规 划
最大收益 或最小消耗分 枝-限界法, FIFO 法
对范围广 的问题可以产 生接近的最优 解
D=i;
6
D=i; Q[i-1].d=(float)*p[i]/w[i]; P+=p[i]; W+=w[i];
用最大收益算法。该算法跟回溯法类似。但分枝限界法需要 O( 2n )的解空间。故
该算法不常用在背包问题求解。回溯法比分枝限界在占用内存方面具有优势。回 溯法占用的内存是 0(解空间的最大路径长度),而分枝限界所占用的内存为 0(解 空间大小)。对于一个子集空间,回溯法需要 0(n)的内存空间,而分枝限界则需 要 0(2n)的空间。虽然最大收益或最小耗费分枝限界在直觉上要好于回溯法,并 且在许多情况下可能会比回溯法检查更少的结点,但在实际应用中,它可能会在 回溯法超出允许的时间限制之前就超出了内存的限制。
三、四种算法的比较与分析 这四种算法都得到了验证,运行结果证明了算法设计是可行的,正确的。通 过对 O-1 背包问题的算法设计及时间复杂度分析可以看出。无论采用贪婪法还是 动态规划法,都是在已知约束条件下求解最大值建立数学模型算法实现的过程; 但算法具体实现和数据结构的建立要用到递归和栈操作。比较贪婪法和动态规划 法。前者的时间复杂度低于后者,从耗费上而言优于后者。但后者的实现算法可 读性要优于前者。 动态规划算法的基本思想是把原问题分解为一系列子问题,然后从这些子问 题中求出原问题的解。回溯其实就是穷举,穷举所有的解,找出解中最优的值。 回溯法在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发 搜索解空间树。回溯法的基本思路是:确定解空间,建立解空间树,用深度优先 搜索算法递归搜索解空间树,并同时注意剪枝,常用的分枝一限界法有最小耗费 法,最大收益法。FIFO(先进先出)法等。0-1 背包问题的分枝一限界算法可以使
wk xk j
k i
xk {0,1}, i k n
Q[i-1].d=*p[i]/w[i]; P+=p[i]; W+=w[i];
n
n
Baidu Nhomakorabea
n
vi yi w1y1 wi zi
i2
i2
i2
} if(W<=c)
return P;<Q[j].d)
n
v1y1 vi zi i2
n
vi yi
i 1
对于 0-1 背包问题,设 A 是能装入容量为 c 的背包的具有最大价值的物 品集合,则 Aj=A-{j}是 n-1 个物品 1,2,...,j-1,j+1,...,n 可装入容量为 c-wj 的背包的具有最大价值的物品集合。
用贪心算法求解 0-1 背包问题的步骤是,首先计算每种物品单位重量的 价值 vi/wi;然后,将物品进行排序,依贪心选择策略,将尽可能多的单位
} if(W<=c) return P;<Q[j].d)
{ f=Q[i].d; Q[i].d=Q[j].d; Q[j].d=f;
} } D]; [i]=w[Q[i-1].ID]; } =0; =0; =c; =n; D]=[j]; delete []Q; delete []; delete []; delete []; return bestp; } void main3() { int m,n; int i=0,j=0; int p[100],w[20],x[20]; while(1) { cout<<"0-1 背包问题--递归法"<<endl; cout<<"请输入背包的容量:"<<endl; cout<<"请输入物品个数:"<<endl; cout<<"请输入物品的重量:"<<endl; cout<<"请输入物品的价值:"<<endl;
的价值:"<<endl;
cout<<" 背 包 的 最


为 :"<<endl<<Knapsack(p,w,m,
n,x)<<endl;
cout<<" 最 优 解 条 件
下选择的背包为:"<<endl;
for(i=1;i<=n;i++)
cout<<x[i]<<"\t"; cout<<endl;
} }
4
jiemian(); switch(getch()) {
case '0':exit(0);break; case '1':main1();break; case '2':main2();break; case '3':main3();break; } } return 0; }
8