poj 1014 Dividing

Description﹡﹡﹡﹡

Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just split the collection in half. But unfortunately, some of the marbles are larger, or more beautiful than others. So, Marsha and Bill start by assigning a value, a natural number between one and six, to each marble. Now they want to divide the marbles so that each of them gets the same total value. Unfortunately, they realize that it might be impossible to divide the marbles in this way (even if the total value of all marbles is even). For example, if there are one marble of value 1, one of value 3 and two of value 4, then they cannot be split into sets of equal value. So, they ask you to write a program that checks whether there is a fair partition of the marbles.

Input

Each line in the input file describes one collection of marbles to be divided. The lines contain six non-negative integers n1 , . . . , n6 , where ni is the number of marbles of value i. So, the example from above would be described by the input-line "1 0 1 2 0 0". The maximum total number of marbles will be 20000. 
The last line of the input file will be "0 0 0 0 0 0"; do not process this line.

Output

For each collection, output "Collection #k:", where k is the number of the test case, and then either "Can be divided." or "Can't be divided.". 
Output a blank line after each test case.

Sample Input

1 0 1 2 0 0 
1 0 0 0 1 1 
0 0 0 0 0 0 

Sample Output

Collection #1:
Can't be divided.

Collection #2:
Can be divided.




很有意义的一道DP题,dd大牛的背包九讲算是认真复习了一遍。
如果本题不是多组数据的话,用简单的多重背包就行了,所以这题就要优化了。

首先,多重背包客转化为 0/1背包问题,就是将多个相同的物品看成独立的个体,就可以套用 0/1背包了。
但如果仅仅这样的话,一定会超时,所以有了个优化————把n个相同的物品拆分成{1,2,4,8,...,2^k,n-2^k+1}个不同的子集,可以证明这些子集可以任意组合成0~~n范围内的任意数,更重要的是,这种拆分方法是分的最少的,优化了算法时间复杂度。
还有一个优化,当一类物品的总花费大于背包最大容量时,可以转换为完全背包问题,因为即使将将这类物品填满背包,也装不完。

#include<iostream>
//#include<fstream> 
#include<string.h> 
using namespace std;
//ifstream fin("cin.in"); 

int f[100001],a[7],ans;bool p=0,flag; 

void CompleteDp(int cost,int value){
     for(int i=cost;i<=ans;i++)
     {
      f[i]=max(f[i],f[i-cost]+value);
      if(f[i]==ans)
      {flag=1;return ;} 
             } 
     } 

void ZerooneDp(int cost,int value){
     for(int i=ans;i>=cost;i--)
     {
      f[i]=max(f[i],f[i-cost]+value);
      if(f[i]==ans)
      {flag=1;return ;} 
             } 
     } 

void MixDp(int cost,int value,int num){
     if(cost*num>=ans)
     {
      CompleteDp(cost,value);
      return ; 
                      } 
     int k=1;
     while(k<=num)
     {
      ZerooneDp(k*cost,k*value); 
      if(flag) return ;  
      num-=k;
      k*=2;    
                 } 
     ZerooneDp(num*cost,num*value); 
     return ;
     } 

int main()
{
    int k=0; 
    while(!cin.eof())
    {
     flag=0;++k;ans=0; 
     memset(f,-1,sizeof(f)); 
     f[0]=0; 

     for(int i=1;i<=6;++i)
     cin>>a[i],ans+=i*a[i];
     
     if(ans==0) return 0; 
     
     if(ans%2) 
     {
      if(p==1) cout<<endl;p=1; 
      cout<<"Collection #"<<k<<":"<<endl; 
      cout<<"Can't be divided."<<endl; continue; 
                    } 
                    
     ans/=2; 
     
     for(int i=1;i<=6;i++)
     {    
      MixDp(i,i,a[i]);
      if(flag)  break;       
             }              
            
     if(flag) 
     {
      if(p==1) cout<<endl;p=1; 
      cout<<"Collection #"<<k<<":"<<endl; 
      cout<<"Can be divided."<<endl; 
                                } 
     else 
     {
      if(p==1) cout<<endl;p=1; 
      cout<<"Collection #"<<k<<":"<<endl; 
      cout<<"Can't be divided."<<endl; 

          } 
                   }   
  //   system("pause"); 
  
    } 
posted on 2012-06-18 23:14  怡红公子  阅读(211)  评论(0编辑  收藏  举报