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 }
  • 相关阅读:
    2、消失的路由,源码的解析基础
    1、v1 与 v2的比较
    uwp 之后台音频
    uwp 之多媒体开发
    UWP 动画之路径
    uwp 动画之圆的放大与缩小
    uwp 中的动画
    C# 输入法
    uwp 之资源的访问
    uwp 之吐司 toast
  • 原文地址:https://www.cnblogs.com/allh123/p/2983236.html
Copyright © 2011-2022 走看看