01揹包问题(动态规划)

01揹包问题

问题描述:在M件物品取出若干件放在空间为W的揹包里,每件物品的体积为W1W2……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 <stdio.h>

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.




点赞