问题描述:在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2……Wn,与之相对应的价值为P1,P2……Pn。
解决方案:动态规划。为什么不能用贪心?贪心虽然会带来每一次最优但是不一定是整体最优。(比如说C的性价比最高,但是放了C就不能放别的了,总价值就不如放A和B的多了)
【题目名称】0/1背包
一个旅行者有一个最多能装m公斤物品的背包,现在有n件物品,它们的重量分别是w1,w2,…,wn,它们的价值分别为c1,c2,…,cn。若每一种物品只有一件,求旅行者能获得的最大总价值。
【输入格式】
第一行:两个整数,m(背包容量,m<=200)和n(物品数量,n<=30)。
第二~n+1行:每行两个整数wi,ci,表示每个物品的重量和价值
【输出格式】
一个数据,表示最大总价值
【输入样例#1】
10 4
2 1
3 3
4 5
7 9
【输出样例#1】
12
【题目分析】
01背包就是意味着每个物品只有一种,可以选择放或者不放。,因此,为了让背包的价值最高,就是要将前i件物品放入一个容量为m的背包来获得最大的价值。
按照这种实现思想,实现的思路如下:
(1) 分析将前i件物品放入容量为m的背包这个问题,将其转化为一个只牵扯前i-1件物品的问题。
a. 如果不放第i件物品,就可以将问题转化为“前i-1件物品放入容量为m的背包”;然后重复之前的过程
b. 如果放第i件物品,就可以将问题转化为“前i-1件物品放入剩下容量为m-w[i]的背包”,此时能获得的最大价值就 是f[i-1,m-w[i]]+v[i].
(2) 根据上述分析,得出状态转移方程:f[i,v]=max{f[i-1,m],f[i-1,m-w[i]]+v[i]};
(3) 由于状态方程,需要一个名为max的函数来比较两个数的较大者;
(4) 输出背包的最大价值
【C代码】
#include
int max(int x,int y){ //求x和y的最大值
if(x>y)
return x;
else
return y;
}
int main(){
int m,n,x,i; //定义变量
int w[30],v[30];
int f[30][200];
scanf("%d%d",&m,&n); //读入背包容量m和物品数量n
for(i=1;i<=n;i++)
scanf("%d %d",&w[i],&v[i]);
for(i=1;i<=n;i++){ //f(i,x)表示前i件物品,总重量不超过x的最优价值
for(x=1;x<=m;x++){
if(x>=w[i])
f[i][x]=max(f[i-1][x-w[i]]+v[i],f[i-1][x]);
else f[i][x]=f[i-1][x];
}
}
printf("%d\n",f[n][m]); //f[n][m]为最优解
return 0;
}
【PASCAL代码】
const
maxm=200 ; maxn =30; //背包容量<=200,物品数量<=30
var
m,n,x,i:integer;
v,w:array[1..maxn] of integer;
f:array[0..maxn,0..maxm] of integer;
functionmax(x,y:integer) :integer; //求x和y的最大值
begin
if x>y then max:=x else max:=y;
end;
begin
readln(m,n); //读入背包容量m和物品数量n
for i:=1 to n do
readln(w[i],v[i]); //读入每个物品的重量和价值
for i:=1 to n do
for x:=1 to m do
begin //f(i,x)表示前i件物品,总重量不超过x的最优价值
if x>=w[i] then f[i,x]:=max(f[i-1,x-w[i]]+v[i],f[i-1,x])
else f[i,x]:=f[i-1,x];
end;
writeln(f[n,m]); //f(n,m)为最优解
end.