用蛮力法、动态规划法和贪心法求解01背包问题
贪心算法-01背包问题

贪⼼算法-01背包问题1、问题描述:给定n种物品和⼀背包。
物品i的重量是wi,其价值为vi,背包的容量为C。
问:应如何选择装⼊背包的物品,使得装⼊背包中物品的总价值最⼤?形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找⼀n元向量(x1,x2,…,xn,), xi∈{0,1}, ∋ ∑ wi xi≤c,且∑ vi xi达最⼤.即⼀个特殊的整数规划问题。
2、最优性原理:设(y1,y2,…,yn)是 (3.4.1)的⼀个最优解.则(y2,…,yn)是下⾯相应⼦问题的⼀个最优解:证明:使⽤反证法。
若不然,设(z2,z3,…,zn)是上述⼦问题的⼀个最优解,⽽(y2,y3,…,yn)不是它的最优解。
显然有∑vizi > ∑viyi (i=2,…,n)且 w1y1+ ∑wizi<= c因此 v1y1+ ∑vizi (i=2,…,n) > ∑ viyi, (i=1,…,n)说明(y1,z2, z3,…,zn)是(3.4.1)0-1背包问题的⼀个更优解,导出(y1,y2,…,yn)不是背包问题的最优解,⽭盾。
3、递推关系:设所给0-1背包问题的⼦问题的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。
由0-1背包问题的最优⼦结构性质,可以建⽴计算m(i,j)的递归式:注:(3.4.3)式此时背包容量为j,可选择物品为i。
此时在对xi作出决策之后,问题处于两种状态之⼀:(1)背包剩余容量是j,没产⽣任何效益;(2)剩余容量j-wi,效益值增长了vi ;使⽤递归C++代码如下:#include<iostream>using namespace std;const int N=3;const int W=50;int weights[N+1]={0,10,20,30};int values[N+1]={0,60,100,120};int V[N+1][W+1]={0};int knapsack(int i,int j){int value;if(V[i][j]<0){if(j<weights[i]){value=knapsack(i-1,j);}else{value=max(knapsack(i-1,j),values[i]+knapsack(i-1,j-weights[i]));}V[i][j]=value;}return V[i][j];}int main(){int i,j;for(i=1;i<=N;i++)for(j=1;j<=W;j++)V[i][j]=-1;cout<<knapsack(3,50)<<endl;cout<<endl;}不使⽤递归的C++代码:简单⼀点的修改//3d10-1 动态规划背包问题#include <iostream>using namespace std;const int N = 4;void Knapsack(int v[],int w[],int c,int n,int m[][10]);void Traceback(int m[][10],int w[],int c,int n,int x[]);int main(){int c=8;int v[]={0,2,1,4,3},w[]={0,1,4,2,3};//下标从1开始int x[N+1];int m[10][10];cout<<"待装物品重量分别为:"<<endl;for(int i=1; i<=N; i++){cout<<w[i]<<" ";}cout<<endl;cout<<"待装物品价值分别为:"<<endl;for(int i=1; i<=N; i++){cout<<v[i]<<" ";}cout<<endl;Knapsack(v,w,c,N,m);cout<<"背包能装的最⼤价值为:"<<m[1][c]<<endl;Traceback(m,w,c,N,x);cout<<"背包装下的物品编号为:"<<endl;for(int i=1; i<=N; i++){if(x[i]==1){cout<<i<<" ";}}cout<<endl;return 0;}void Knapsack(int v[],int w[],int c,int n,int m[][10]){int jMax = min(w[n]-1,c);//背包剩余容量上限范围[0~w[n]-1] for(int j=0; j<=jMax;j++){m[n][j]=0;}for(int j=w[n]; j<=c; j++)//限制范围[w[n]~c]{m[n][j] = v[n];}for(int i=n-1; i>1; i--){jMax = min(w[i]-1,c);for(int j=0; j<=jMax; j++)//背包不同剩余容量j<=jMax<c{m[i][j] = m[i+1][j];//没产⽣任何效益}for(int j=w[i]; j<=c; j++) //背包不同剩余容量j-wi >c{m[i][j] = max(m[i+1][j],m[i+1][j-w[i]]+v[i]);//效益值增长vi }}m[1][c] = m[2][c];if(c>=w[1]){m[1][c] = max(m[1][c],m[2][c-w[1]]+v[1]);}}//x[]数组存储对应物品0-1向量,0不装⼊背包,1表⽰装⼊背包void Traceback(int m[][10],int w[],int c,int n,int x[]){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;}运⾏结果:算法执⾏过程对m[][]填表及Traceback回溯过程如图所⽰:从m(i,j)的递归式容易看出,算法Knapsack需要O(nc)计算时间; Traceback需O(n)计算时间;算法总体需要O(nc)计算时间。
动态规划法求01背包问题

动态规划法求01背包问题思路状态表⽰:f[i][j]表⽰前i个物品在容量为j的背包下的最⼤价值v[i]表⽰第i个物品的价值,w[i]表⽰第i个物品的重量状态转换:对于第i个物品如果当前背包不可以装下这个物品,那么当前的f[i][j] = f[i - 1][j],也就是上⼀个状态的最⼤价值如果当前背包可以装下这个物品,那么当前的f[i][j] = f[i - 1][j - v[i]] + w[i]和f[i - 1][j]取较⼤的那⼀个,第⼀个是考虑把第i个物品装⼊背包,那么背包物品的价值就是前i-1个物品装⼊容量为j-w[i]再加上第i个物品v[i]的价值,第⼆个是不把当前物品装⼊背包的价值,两个取⼤的那⼀个作为最优解代码详解:1. 0/1背包问题#include<iostream>using namespace std;const int N = 1e3 + 10;int f[N], w[N], v[N];int main(){int n, c;cin >> n >> c;for(int i = 1; i <= n; i ++ )cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++)for(int j = c; j >= 0 && j >= v[i]; j --)f[j] = max(f[j], f[j - v[i]] + w[i]);cout << f[c] << endl;return 0;}}完全背包问题(每个物品可以使⽤⽆数次f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])完全背包问题本来应该是在背包问题上再加⼀个循环的,但是可以推导出下⾯这个样⼦f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i])为什么呢,只是把0/1背包问题的f[i - 1][j - v[i] + w[i])的i-1换成了i就可以了?从头来说:完全背包问题,对于第i个物品,假设剩下的背包容量还可以装n个这个物品,那么⼀共就有n+1中决策⽅案,还有⼀种⽅案就是⼀个都不选那么对于第i个物品:它的最⼤价值就是f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]), f[i - 1][j - 2 * v[i]] + 2 * w[i]....)⼀直到n为⽌(①式)令 j = j - v[i] 那么f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i].....)(②式)然后发现⼆式中的右边⽐较像⼀式中的第⼆项到最后⼀项,就是每⼀项都少了⼀个w[i]把⼆式带⼊⼀式,那么⼀式就是 f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]), 就是下⾯这个状态⽅程啦 ;#include<iostream>using namespace std;const int N = 1e3 + 10;int f[N][N], w[N], v[N];int main(){int n, c;cin >> n >> c;for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i];for(int i = 1; i <= n; i ++ ){for(int j = 1; j <= c; j ++ ){f[i][j] = f[i - 1][j];if(j >= v[i])f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);}}cout << f[n][c] << endl;return 0;}完全背包优化:#include<iostream>using namespace std;const int N = 1e3 + 10;int f[N], w[N], v[N];int main(){int n, c;cin >> n >> c;for(int i = 1; i <= n; i ++)cin >> v[i] >> w[i]; for(int i = 1; i <= n; i ++ )for(int j = v[i]; j <= c; j ++ )//从前往后更新 f[j] = max(f[j], f[j - v[i]] + w[i]);cout << f[c] << endl;return 0;}。
利用动态规划解决01背包问题01背包问题动态规划

利用动态规划解决01背包问题01背包问题动态规划背包问题是一个经典的动态规划模型,很多关于算法的教材都把它作为一道例题,该问题既简单又容易理解,而且在某种程度上还能够揭示动态规划的本质。
将具有不同重量和价值的物体装入一个有固定载重量的背包,以获取最大价值,这类问题被称为背包问题。
背包问题可以扩展出很多种问题,而01背包问题是最常见、最有代表性的背包问题。
一、问题描述给定一个载重量为M的背包及n个物体,物体i的重量为wi、价值为pi,1≤i≤n,要求把这些物体装入背包,使背包内的物体价值总量最大。
此处我们讨论的物体是不可分割的,通常称这种物体不可分割的背包问题为01背包问题。
二、基本思路01背包问题的特点是:每种物体只有一件,可以选择放或者不放。
假设:xi表示物体i被装入背包的情况,xi=0,1。
当xi=0时,表示物体没有被装入背包;当xi=1时,表示物体被装入背包。
根据问题的要求,有如下的约束方程(1)和目标函数(2):三、利用动态规划法求解01背包问题(一)动态规划算法的基本思想动态规划算法通常用于求解具有某种最优性质的问题。
在这类问题中,可能会有许多可行解。
每一个解都对应于一个值,我们希望找到具有最优值的解。
动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。
若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算很多次。
如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。
我们可以用一个表来记录所有已解的子问题的答案。
不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中,这就是动态规划法的基本思路。
具体的动态规划算法多种多样,但它们具有相同的填表格式。
(二)算法设计假定背包的载重量范围为0~m。
蛮力法、动态规划法 求解01背包问题

else
v[i][j]=v[i-1][j];
}
else v[i][j]=v[i-1][j];
}
return v[n][m];
}
int main()
{
int m,n;int i,j;
cout<<"请输入背包的承重量:"<<endl;
2)复杂度分析:2n
2、动态规划法
1)基本思想:Dynamic programming is a technique for solving problems with overlapping subproblems.The function:
V(i,0)=V(0,j)=0;(1)
V(i-1,j)j<w
if (cur_weight <= capacity && cur_value > max_value) {
max_value = cur_value;
}
return;
}
c[d] = 0;
MFKnapsack(capacity, values, weights, c,
d + 1, max_value);
cout << MFKnapsack(capacity, values, weights, n) << endl;
return 0;
}
(2)Dynamic Programming
#include<iostream.h>
#include<string.h>
int v[10][100];//对应每种情况的最大价值
实验项目三 用蛮力法、动态规划法和贪心法求解背包问题

实验项目三 用蛮力法、动态规划法和贪心法求解0/1背包问题实验目的1、学会背包的数据结构的设计,针对不同的问题涉及到的对象的数据结构的设计也不同;2、对0-1背包问题的算法设计策略对比与分析。
实验内容:0/1背包问题是给定n 个重量为{w 1, w 2, … ,wn }、价值为{v 1, v 2, … ,vn }的物品和一个容量为C 的背包,求这些物品中的一个最有价值的子集,并且要能够装到背包中。
在0/1背包问题中,物品i 或者被装入背包,或者不被装入背包,设xi 表示物品i 装入背包的情况,则当xi =0时,表示物品i 没有被装入背包,xi =1时,表示物品i 被装入背包。
根据问题的要求,有如下约束条件和目标函数:于是,问题归结为寻找一个满足约束条件式1,并使目标函数式2达到最大的解向量X =(x 1, x 2, …, xn )。
背包的数据结构的设计:typedef struct object{int n;//物品的编号int w;//物品的重量int v;//物品的价值}wup;wup wp[N];//物品的数组,N 为物品的个数int c;//背包的总重量1、蛮力法蛮力法是一种简单直接的解决问题的方法,常常直接基于问题的描述和所涉及的概念定义。
蛮力法的关键是依次处理所有的元素。
用蛮力法解决0/1背包问题,需要考虑给定n 个物品集合的所有子集,找出所有可能的子集(总重量不超过背包容量的子集),计算每个子集的总价值,然后在他们中找到价值最大的子集。
所以蛮力法解0/1背包问题的关键是如何求n 个物品集合的所有子集,n 个物品的子集有2的n 次方个,用一个2的n 次方行n 列的数组保存生成的子集,以下是生成子集的算法:⎪⎩⎪⎨⎧≤≤∈≤∑=)1(}1,0{1n i x C x w i n i i i (式1)∑=ni i i x v 1max (式2)void force(int a[16][4])//蛮力法产生4个物品的子集{int i,j;int n=16;int m,t;for(i=0;i<16;i++){ t=i;for(j=3;j>=0;j--){m=t%2;a[i][j]=m;t=t/2;}}for(i=0;i<16;i++)//输出保存子集的二维数组{for(j=0;j<4;j++){printf("%d ",a[i][j]);}printf("\n");}}以下要依次判断每个子集的可行性,找出可行解:void panduan(int a[][4],int cw[])////判断每个子集的可行性,如果可行则计算其价值存入数组cw,不可行则存入0{int i,j;int n=16;int sw,sv;for(i=0;i<16;i++){sw=0;sv=0;for(j=0;j<4;j++){sw=sw+wp[j].w*a[i][j];sv=sv+wp[j].v*a[i][j];}if(sw<=c)cw[i]=sv;elsecw[i]=0;}在可行解中找出最优解,即找出可行解中满足目标函数的最优解。
动态规划算法-01背包问题

intn = 5;//物品个数
//c[i][j]表示前i个物品能装入容量为Wj的背包中的最大价值
intc[][] =newint[n+1][m+1];
intpath[][] =newint[n+1][m+1];
//初始化第一列和第一行
for(inti=0;i<c.length;i++){
动态规划算法是非常有效的算法技术,那么什么时候使用它呢?或者说其运用场景是什么?若求解问题具有一下性质,可以考虑使用动态规划法:
1、最优子结构:如果一个问题的最优解中包含其子问题的最优解,就是说该问题具有最优子结构。这时候贪婪算法可能也使用求解此类问题
2、重叠子问题:重叠子问题是指用来求解问题的递归算法可以反复的解同样的问题,而不是总在产生新的问题,即当一个递归算法不断的调用同一个问题时,就说该问题包含重叠子问题,此时若使用分治法递归求解时,则每次遇到子问题都会视为新问题,会极大降低效率,而动态规划法对每个子问题仅计算一次,把解保存到在一个需要时就可以查看的表中
根据上述分析,设c[i , w]表示背包容量为w时i个物品最优解的总价值,得到公式:
0i = 0或w = 0
C[i , w ] =c[i – 1, w] wi > w
max{ c[i–1 ,w–wi ] + vi , c[i – 1,w]} i > 0且wi <= w
2、根据物品的件数i = 5、包的容量W = 17规划“价值”分布矩阵,如下图所示:
{
int i,w;
//为二维数组申请空间
int** c = (int**)malloc(sizeof(int *)*(n+1));
用贪心法求解0-1背包问题

算法设计与分析期末论文题目用贪心法求解“0-1背包问题”专业计算机科学与技术班级09计算机一班学号0936021姓名黄帅日期2011年12月28日一、0-1背包问题的算法设计策略分析1.引言对于计算机科学来说,算法的概念是至关重要的,例如,在一个大型软件系统的开发中,设计出有效的算法将起决定性的作用。
算法是解决问题的一种方法或一个过程。
程序是算法用某种设计语言具体实现描。
计算机的普及极大的改变了人们的生活。
目前,各行业、各领域都广泛采用了计算机信息技术,并由此产生出开发各种应用软件的需求。
为了以最小的成本、最快的速度、最好的质量开发出适合各种应用需求的软件,必须遵循软件工程的原则。
设计一个高效的程序不仅需要编程小技巧,更需要合理的数据组织和清晰高效的素算法,这正是计算机科学领域数据结构与算法设计所研究的主要内容。
2. 算法复杂性分析的方法介绍算法复杂性是算法运行所需要的计算机资源的量,需要时间资源的量称为时间复杂性,需要的空间资源的量称为空间复杂性。
这个量应该只依赖于算法要解的问题的规模、算法的输入和算法本身的函数。
如果分别用N 、I 和A 表示算法要解问题的规模、算法的输入和算法本身,而且用C 表示复杂性,那么,应该有C=F(N,I,A)。
一般把时间复杂性和空间复杂性分开,并分别用T 和S 来表示,则有: T=T(N,I)和S=S(N,I) 。
(通常,让A 隐含在复杂性函数名当中最坏情况下的时间复杂性:最好情况下的时间复杂性:平均情况下的时间复杂性:其中DN 是规模为N 的合法输入的集合;I*是DN 中使T(N, I*)达到Tmax(N)的合法输入; 是中使T(N, )达到Tmin(N)的合法输入;而P(I)是在算法的应用中出现输入I 的概率。
算法复杂性在渐近意义下的阶:渐近意义下的记号:O 、Ω、θ、o 设f(N)和g(N)是定义在正数集上的正函数。
O 的定义:如果存在正的常数C 和自然数N0,使得当N ≥N0时有f(N)≤Cg(N),则称函数f(N)当N 充分大时上有界,且g(N)是它的一个上界,记为f(N)=O(g(N))。
用动态规划法求解01背包问题

用动态规划法求解0/1背包问题实验目的:1、掌握动态规划算法求解问题的一般特征和步骤。
2、使用动态规划法编程,求解0/1背包问题。
实验要求:1、掌握动态规划算法求解问题的一般特征和步骤。
2、使用动态规划法编程,求解0/1背包问题。
实验内容:1、问题描述:给定n种物品和一个背包,物品I的重量是Wi,其价值为Vi,问如何选择装入背包的物品,使得装入背包的物品的总价值最大?2、算法描述。
3、程序实现给出实例测试结果。
程序清单:#include<iostream>#include<iomanip>using namespace std;int c[50][50];int w[10],v[10];int x[10];int n;void KNAPSACK_DP(int n,int W){for(int k=0;k<=W;k++)c[0][k]=0;for(int i=1;i<=n;i++){c[i][0]=0;for(int k=1;k<=W;k++){if(w[i]<=k){if(v[i]+c[i-1][k-w[i]]>c[i-1][k])c[i][k]=v[i]+c[i-1][k-w[i]];elsec[i][k]=c[i-1][k];}elsec[i][k]=c[i-1][k];}}}void OUTPUT_SACK(int c[50][50],int k) {for(int i=n;i>=2;i--){if(c[i][k]==c[i-1][k])x[i]=0;else{x[i]=1;k=k-w[i];}}x[1]=(c[1][k]?1:0);for(int i=1;i<=n;i++)cout<<setw(4)<<x[i];}void main(){int m;cout<<"输入物品个数:";cin>>n;cout<<"依次输入物品的重量:"<<endl; for(int i=1;i<=n;i++)cin>>w[i];cout<<"依次输入物品的价值:"<<endl; for(int i=1;i<=n;i++)cin>>v[i];cout<<"输入背包最大容量:";cin>>m;for(int i=1;i<=m;i++)cout<<setw(4)<<i;cout<<endl;KNAPSACK_DP(n,m);cout<<"构造最优解过程如下:"<<endl; for(int j=1;j<=5;j++){for(int k=1;k<=m;k++)cout<<setw(4)<<c[j][k];cout<<endl;}cout<<"最优解为:"<<endl;OUTPUT_SACK(c,m);}运行结果:输入物品个数:5依次输入物品的重量:3 4 7 8 9依次输入物品的价值:4 5 10 11 13输入背包最大容量:171 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 构造最优解过程如下:0 0 4 4 4 4 4 4 4 4 4 4 4 4 4 4 40 0 4 5 5 5 9 9 9 9 9 9 9 9 9 9 90 0 4 5 5 5 10 10 10 14 15 15 15 19 19 19 19 0 0 4 5 5 5 10 11 11 14 15 16 16 19 21 21 21 0 0 4 5 5 5 10 11 13 14 15 17 18 19 21 23 24 最优解为:0 0 0 1 1实验体会:通过该实验,使用动态规划法编程,求解0/1背包问题,掌握动态规划算法求解问题的一般特征和步骤。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(3).价格空间比最优的贪心策略结果
第四章:分析和讨论
算法的时间复杂度和空间复杂度的分析,对算法进一步改进的讨论。
附录:源代码(基于C语言的)
1.蛮力法求解01背包问题源程序:
#include "stdafx.h"
#include "stdlib.h"
#include "stdio.h"
贪心法求解的问题的特征:
(1)最优子结构性质
当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质,也称此问题满足最优性原理。
(2)贪心选择性质
所谓贪心选择性质是指问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来得到。
用贪心法求解问题应该考虑如下几个方面:
(1)候选集合C:为了构造问题的解决方案,有一个候选集合C作为问题的可能解,即问题的最终解均取自于候选集合C。例如,在付款问题中,各种面值的货币构成候选集合。
#define N 4
(2)解集合S:随着贪心选择的进行,解集合S不断扩展,直到构成一个满足问题的完整解。例如,在付款问题中,已付出的货币构成解集合。
(3)解决函数solution:检查解集合S是否构成问题的完整解。例如,在付款问题中,解决函数是已付出的货币金额恰好等于应付款。
(4)选择函数select:即贪心策略,这是贪心法的关键,它指出哪个候选对象最有希望构成问题的解,选择函数通常和目标函数有关。例如,在付款问题中,贪心策略就是在候选集合中选择面值最大的货币。
第一章:简介(Introduction)
0/1背包问题是给定n个重量为{w1,w2, …,wn}、价值为{v1,v2, …,vn}的物品和一个容量为C的背包,求这些物品中的一个最有价值的子集,并且要能够装到背包中。
在0/1背包问题中,物品i或者被装入背包,或者不被装入背包,设xi表示物品i装入背包的情况,则当xi=0时,表示物品i没有被装入背包,xi=1时,表示物品i被装入背包。根据问题的要求,有如下约束条件和目标函数:
sv=sv+wp[j].v*a[i][j];
}
if(sw<=c)
cw[i]=sv;
else
cw[i]=0;
}
在可行解中找出最优解,即找出可行解中满足目标函数的最优解。以下是找出最优解的算法:
int findmax(int x[16][4],int cv[])//可行解保存在数组cv中,最优解就是x数组中某行的元素值相加得到的最大值
动态规划法将待求解问题分解成若干个相互重叠的子问题,每个子问题对应决策过程的一个阶段,一般来说,子问题的重叠关系表现在对给定问题求解的递推关系(也就是动态规划函数)中,将子问题的解求解一次并填入表中,当需要再次求解此子问题时,可以通过查表获得该子问题的解而不用再次求解,从而避免了大量重复计算。
动态规划法设计算法一般分成三个阶段:
}
}
然后再用贪心策略选择的算法如下:
int tx_findmaxvalue(wup wp[],int x[])//用贪心算法找出放入背包中物品的最佳组合
//wp为指向物品数组,x是存放解向量的数组
{
int i;
int cw,maxvalue;
cw=C;//cw为中间变量,用来临时存储背包的总重量
bublesort(wp);
cw=cw-wp[i].w; //每放入一件物品背包的总重量减少
}
else
x[wp[i].n-1]=0;
}
return maxvalue;
}
第三章:测试结果(Testing Results)
1.蛮力法测试结果:
输入完毕后按Enter键有如下结果:
2.动态规划法调试结果
3.贪心法调试结果:
(1).空间最优的贪心策略结果
}
}
//逆推求解
j=C;
for(i=N;i>0;i--)
{
if(value[i][j]>value[i-1][j])
{
x[i-1]=1;//是否被选中的向量的下标也是从0开始
j=j-wp[i-1].w;//存放物品的下标从0开始
}
else
x[i-1]=0;
}
maxvalue=value[N][C];//最大值
{
int max;
int i,j;
max=0;
for(i=0;i<16;i++)
{
if(cv[i]>max)
{max=cv[i];
j=i;
}
}
printf("\n最好的组合方案是:");
for(i=0;i<4;i++)
{
printf("%d ",x[j][i]);
}
return max;
}
。
2、动态规划法
(1)背包容量不足以装入物品i,则xi=0,背包不增加价值;
(2)背包容量可以装入物品i,则xi=1,背包的价值增加了vi。
这两种情况下背包价值的最大者应该是对xi决策后的背包价值。令V(i, j)表示在前i(1≤i≤n)个物品中能够装入容量为j(1≤j≤C)的背包中的物品的最大值,则可以得到如下动态规划函数:
Outputwp(wp);
maxvalue=0;
for(i=0;i<N;i++)//对已排过序的数组,顺序选择物品是否可以放入背包
{
if(wp[i].w<cw) //如果物品的重量小于背包的重量,则放入背包
{
x[wp[i].n-1]=1; //该物品被选中,对应的向量为1
maxvalue=maxvalue+wp[i].v;//累加价值
以下是动态规划法求解背包问题的算法:
int findmaxvalue(wup *p,int x[])//x数组用来存放可行解,p是指向存放物品数组的指针
{
int i,j;
int maxvalue;
int value[N+1][C+1];
for(j=0;j<=C;j++)
value[0][j]=0; //初始化第0行
(5)可行函数feasible:检查解集合中加入一个候选对象是否可行,即解集合扩展后是否满足约束条件。例如,在付款问题中,可行函数是每一步选择的货币和已付出的货币相加不超过应付款。
背包问题至少有三种看似合理的贪心策略:
(1)选择价值最大的物品,因为这可以尽可能快地增加背包的总价值。但是,虽然每一步选择获得了背包价值的极大增长,但背包容量却可能消耗得太快,使得装入背包的物品个数减少,从而不能保证目标函数达到最大。
(2)选择重量最轻的物品,因为这可以装入尽可能多的物品,从而增加背包的总价值。但是,虽然每一步选择使背包的容量消耗得慢了,但背包的价值却没能保证迅速增长,从而不能保证目标函数达到最大。
(3)选择单位重量价值最大的物品,在背包价值增长和背包容量消耗两者之间寻找平衡。
应用第三种贪心策略,每次从物品集合中选择单位重量价值最大的物品,如果其重量小于背包容量,就可以把它装入,并将背包容量减去该物品的重量,然后我们就面临了一个最优子问题——它同样是背包问题,只不过背包容量减少了,物品集合减少了。因此背包问题具有最优子结构性质。
先按单位重量价值最大对物品进行排序,用冒泡排序算法进行排序的算法如下:
void bublesort(wup wp[])
{
int i,k;
wup p;
int flag;
for(i=1;i<N;i++)
{
flag = 0;
for (k = N-1; k >=i; k--)
{
if (wp[k-1].v/wp[k-1].w<wp[k].v/wp[k].w)//比较物品单位重量的价值,按从大到小排序
算法设计与分析
项 目 名 称:用蛮力法、动态规划法和贪心法求解0/1背包问题
作者姓名:余武丹
李红波
刘红梅
完成日期:2013年9月20日
第一章:简介(Introduction)
第二章:算法定义(Algorithm Specification)
第三章:测试结果(Testing Results)
第四章:分析和讨论
{
p.n =wp[k-1].n;
p.v=wp[k-1].v;
p.w=wp[k-1].w;
wp[k-1].n=wp[k].n;
wp[k-1].v=wp[k].v;
wp[k-1].w=wp[k].w;
wp[k].n=p.n;
wp[k].v=p.v;
wp[k].w=p.w;
flag=1;
}
}
if(flag==0)break;
{ t=i;
for(j=3;j>=0;j--)
{
m=t%2;
a[i][j]=m;
t=t/2;
}
}
for(i=0;i<16;i++)//输出保存子集的二维数组
{
for(j=0;j<4;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
}
以下要依次判断每个子集的可行性,找出可行解:
int c;//背包的总重量
第二章:算法定义(Algorithm Specification)
1、蛮力法
蛮力法是一种简单直接的解决问题的方法,常常直接基于问题的描述和所涉及的概念定义。蛮力法的关键是依次处理所有的元素。