zoukankan      html  css  js  c++  java
  • 多重背包POJ1276不要求恰好装满 poj1014多重背包恰好装满

    二进制压缩,看背包九讲啦,写的很详细了,不赘述````

    先贴不要求恰好装满的情形

    POJ 1276

    二进制压缩:

     1 #include <cstdio>
     2 #include <cstring>
     3 int f[100005];//容量为i时最多能装多少
     4 int p[12000];//物品拆分
     5 int main()
     6 {
     7     int n,cash;
     8     while(~scanf("%d%d",&cash,&n))
     9     {
    10         int vi,num;//物品价值,数量
    11         int cur = 0;
    12         memset(f,0,sizeof(f));
    13         for(int i=0; i<n; i++)
    14         {
    15             scanf("%d%d",&num,&vi);
    16             int k = 1;
    17             //把物品拆分成num = 1 + 2 + 4 + 8 + 16 + 32 + ``` + 2^k + l(剩余的值)
    18             //假设某物品有10件,拆成7=1+2+4+3。。这样,10件这样的物品变成了4件物品,用这四种物品可组和出
    19             //0-10的每一种情形,原理在于二进制,每位取0或者1,但是能表示出很多数
    20             //多重背包转化成了0-1背包
    21             while(num-k > 0)
    22             {
    23                 p[cur]= vi*k;
    24                 num -= k;
    25                 k *= 2;
    26                 cur++;
    27             }
    28             p[cur] = vi*num;
    29             cur++;
    30         }
    31         for(int i=0; i< cur; i++)
    32         {
    33             for(int j = cash; j >= p[i]; j--)
    34             {
    35                 if(f[j] < f[j-p[i]]+p[i])
    36                     f[j] = f[j-p[i]]+p[i];
    37             }
    38         }
    39         printf("%d\n",f[cash]);
    40     }
    41     return 0;
    42 }
    View Code

    另一种算法,感觉挺好的。。。

     1 #include <cstdio>
     2 #include <cstring>
     3 //#define debug
     4 int count[100005];//被使用的次数
     5 bool vis[100005]; //是否恰好能被零散货币表示
     6 int main()
     7 {
     8     int n,i,j,cash;
     9 #ifdef debug
    10     freopen("in.cpp","r",stdin);
    11 #endif
    12     while(~scanf("%d",&cash))
    13     {
    14         scanf("%d",&n);
    15         memset(vis,0,sizeof(vis));//vis用来表示是否恰好被装满
    16         vis[0] = 1;
    17         for(i=0; i<n; ++i)
    18         {
    19             int v,num;
    20             scanf("%d%d",&num,&v);
    21             memset(count,0,sizeof(count));//用来记录该物品被用过几次,每次都得重新赋值,麻烦的
    22             for(j=v; j<=cash; ++j)
    23             {
    24                 int t = j-v;
    25                 if(!vis[j] && vis[t] && count[t] < num)//用过的次数>=num。就不行了
    26                 {
    27                     vis[j] = 1;
    28                     count[j] = count[t] + 1;
    29                 }
    30             }
    31         }
    32         for(i=cash; i>=0; --i)
    33         {
    34             if(vis[i])
    35             {
    36                 printf("%d\n",i);
    37                 break;
    38             }
    39         }
    40     }
    41     return 0;
    42 }
    View Code

    该算法复杂度为O(N*M),貌似和单调队列优化的复杂度差不多

    再贴恰好要装满的情形

    POJ 1014

    View Code
     1 #include <cstdio>
     2 int f[500000];
     3 int p[2000];
     4 int main()
     5 {
     6     int ser = 0;
     7     while(1)
     8     {
     9         int n[7];
    10         int sum =0;
    11         int cur =0;
    12         for(int i=1; i<= 6; i++)
    13         {
    14             scanf("%d",&n[i]);
    15             sum += i*n[i];
    16             int k = 1;
    17             while(n[i] - k > 0)
    18             {
    19                 p[cur] = i*k;
    20                 cur++;
    21                 n[i] -= k;
    22                 k *= 2;
    23             }
    24             p[cur] = n[i]*i;
    25             cur++;
    26         }
    27         if(sum == 0) break;
    28         if(sum%2 == 1)
    29         {
    30             printf("Collection #%d:\n",++ser);
    31             printf("Can't be divided.\n\n");
    32             continue;
    33         }
    34         sum = sum/2;
    35         for(int i=1 ; i <= sum; i++)
    36             f[i] = -1000;
    37         f[0] = 0;
    38         for(int i=0; i < cur && f[sum] < 0; i++)
    39         {
    40             for(int j= sum; j >0; j--)
    41             {
    42                 if(j - p[i] < 0) continue;
    43                 if(f[j-p[i]] >= 0 && f[j-p[i]]+p[i] > f[j])
    44                 {
    45                     f[j] = f[j-p[i]]+p[i];
    46                     if(j == sum )  break;
    47                 }
    48             }
    49         }
    50         printf("Collection #%d:\n",++ser);
    51         if(f[sum] == sum)
    52             printf("Can be divided.\n\n");
    53         else
    54             printf("Can't be divided.\n\n");
    55     }
    56     return 0;
    57 }
  • 相关阅读:
    HDU1720 A+B Coming
    HDU1390 ZOJ1383 Binary Numbers
    HDU1390 ZOJ1383 Binary Numbers
    HDU2504 又见GCD
    HDU2504 又见GCD
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1335 POJ1546 UVA389 UVALive5306 ZOJ1334 Basically Speaking
    HDU1020 ZOJ2478 Encoding
    HDU1020 ZOJ2478 Encoding
    HDU2097 Sky数
  • 原文地址:https://www.cnblogs.com/allh123/p/2983236.html
Copyright © 2011-2022 走看看