背包九讲之一(01背包)

  1 /*

  2 有n个物品和一个容量为V的背包,第i件物品的费用是c[i],价值是w[i]

  3 求解哪些物品装入背包使价值总和最大

  4 dp[i][j]  dp[i][j] 为前i件物品放进容量为j的背包的最大价值

  5 dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);

  6 */

  7 #include <stdio.h>

  8 #include <string.h>

  9 int dp[111][1111];

 10 int dp2[1001];

 11 int c[111],w[111];

 12 bool flag[111];

 13 inline int max(const int &a, const int &b)

 14 {

 15     return a < b ? b : a;

 16 }

 17 int main()

 18 {

 19     int n,v,i,j;

 20     while(scanf("%d%d",&n,&v)!=EOF)

 21     {

 22         memset(dp,0,sizeof(dp));

 23         dp2[0] = 0;

 24         for(i=1; i<=n; ++i)

 25             dp2[i] = 1<<30;

 26         memset(flag,false,sizeof(flag));

 27         for(i=1; i<=n; ++i)

 28             scanf("%d",&w[i]);

 29         for(i=1; i<=n; ++i)

 30             scanf("%d",&c[i]);

 31         for(i=1; i<=n; ++i)//时间空间复杂度均为O(VN)

 32             for(j=0; j<=v; ++j)

 33             {

 34                 dp[i][j] = dp[i-1][j];

 35                 if(j>=c[i])

 36                     dp[i][j] = max(dp[i][j],dp[i-1][j-c[i]]+w[i]);

 37             }

 38         for(i=1; i<=n; ++i)

 39         for(j=v; j>=0; --j)

 40         {

 41             if(j>=c[i])

 42                 dp2[j] = max(dp2[j],dp2[j-c[i]]+w[i]);

 43         }

 44         printf("%d\n",dp[n][v]);

 45         printf("%d\n",dp2[v]);

 46         /*时间复杂度不能优化了,但是空间可以优化到O(V)

 47         for(i=1; i<=n; ++i)

 48         for(j=v; j>=0; --j)//将循环改为这样也是成立的

 49         那么每一个dp[i][j] 都是继承自上一层的dp[i-1][j] 或者dp[i-1][j-c[i]]

 50         那么j是大于等于j或者j-c[i]的。

 51         那么就可以这样

 52         for(i=1; i<=n; ++i)

 53         for(j=v; j>=c[i]; --j)//必须是从后忘前

 54         {

 55             dp2[j] = max(dp2[j],dp[j-c[i]+w[i]]);//这一层继承继承自上一层,这种数组叫做滚动数组

 56         }

 57         */

 58         //下面是判断哪几个背包被选

 59         int Max = dp[n][v];

 60         for(i=n; i>=1; --i)

 61         {

 62             if(dp[i-1][v]>= Max)

 63                 flag[i] = false;

 64             else

 65             {

 66                 flag[i] = true;

 67                 v -= c[i];

 68                 Max -= w[i];

 69             }

 70         }

 71         if(flag[1])

 72                 printf("1");

 73             else

 74                 printf("0");

 75         for(i=2; i<=n; ++i)

 76             if(flag[i])

 77                 printf(" 1");

 78             else

 79                 printf(" 0");

 80         printf("\n");

 81     }

 82     return 0;

 83 }

 84 /*

 85 5 10

 86 6 3 5 4 6

 87 2 2 6 5 4

 88 Sample Output:

 89 15

 90 1 1 0 0 1

 91 */

 92 /*

 93 另外还有就是求背包的最优解过程中,有两种要求:

 94 (1)要求背包装满,且价值最大(所以可能导致无解的情况发生)

 95 (2)只要求价值最大

 96 这两种问法差别在于初始化

 97 (1)将dp[0][0]初始化为0,其他的初始化为-INF,这是由题目的性质导致的

 98     初始的时候什么都不装,但是背包有容量而没装满是不合法的,所以定义-INF为不合法的

 99     如果要求背包装满,那么dp[i][j]表示的含义就变为了前i个物品装满容量为j的背包的最大价值

100     dp[i][j] = max(dp[i-1][j],dp[i-1][j-c[i]]+w[i]);

101     如果dp[i-1][j],dp[i-1][j-c[i]]+w[i] ,这两个状态是不合法的,那么dp[i][j]也是不合法的

102 (2)都初始化为0

103         

104 */

 

你可能感兴趣的:(背包)