zoj 1149 Dividing

1到6的卡分别各有有限制的张数,问能不能恰好分,总张数不能超过20000.

很明显是多重背包问题,上去果写了个三重循环,然后就T了,重新打开背包九讲,找到了多重背包的二进制拆分优化,把其中一维n的复杂度简化为logn的复杂度。

二进制拆分优化:就是1,2,4,2^k(满足和小于分解数最大的k),二进制优化可行的原因,因为可以用二进制数表示任意不同小于等于k的数。

注意:数组不要开小,RE了

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
#include<string>
using namespace std;
int a[7];
int dp[60005];
int sum=0;
int num[60006];
int kk;
void bin(int n,int k)  //多重背包的二进制拆分
{
    int i,x;
    for(i=0; ; i++)
    {
        x = 1<<i;
        if(k<x)
            break;
         k-=x;
        num[kk++] = x*n;
    }
    if( k != 0 )
        num[kk++] = n*k;
}
int main()
{
   // freopen("input.txt","r",stdin);
  int cas=1;
  while(1)
  {
       memset(num,0,sizeof(num));
       memset(dp,0,sizeof(dp));
      kk=0;
      sum=0;
      for(int i=1;i<7;i++)
      {
        scanf("%d",&a[i]);
        sum+=a[i]*i;
        bin(i,a[i]);
      }
      if(!sum)
        break;
      printf("Collection #%d:\n",cas++);
      if(sum%2==1)
      {
            printf("Can't be divided.\n\n");
            continue;
      }
      sum/=2;
    //  printf("%d\n",kk);
     for(int i=0;i<kk;i++)//01
           for(int k=sum;k>=num[i];k--)
           {
              dp[k]=max(dp[k],dp[k-num[i]]+num[i]);
           }
           if(dp[sum]==sum)
           {
               printf("Can be divided.\n\n");
           }
           else
           {
                printf("Can't be divided.\n\n");
           }
  }
}
posted @ 2015-11-01 16:21  acliang  阅读(313)  评论(0编辑  收藏  举报