POJ 1014 Dividing (母函数优化)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/AgoniAngel/article/details/51900775

Description

每一行输入6个数,第i个数表示价值为i的珠宝的个数,问这些珠宝是不是能等价平分给两个人。


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.


思路

母函数模板题,先算出这些珠宝的总价值sum,利用母函数判断sum/2的系数是否为0。如果不为0就能等价平分。

但仅仅套模板做会超时,因为珠宝总个数最大达到20000。因此需要剪枝。

网上题解提到只要输入的数大于6,如果是大于6的奇数,那么这个数用5代替结果是一样的;如果是大于6的偶数,那么这个数用6代替结果是一样的.

这样确实就过了,而且是0ms。

另外我发现,这种改写不仅可以用6作分界线,任何大于6的数字也都行。只是6是能改写的最小的分界线。

没有明白其中的道理,留个解释以后看。


#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
typedef long long LL;
using namespace std;
const int N = 200;
int c1[N],c2[N],a[6];

int main(){
    int cas=1;
    while(~scanf("%d%d%d%d%d%d",&a[0],&a[1],&a[2],&a[3],&a[4],&a[5])){
        memset(c1,0,sizeof(c1));
        memset(c2,0,sizeof(c2));
        c1[0]=1;

        int cnt=0,sum=0;
        for(int i=0;i<6;i++){
            if(a[i]>6){
                if(a[i]%2==1) a[i]=5;
                else a[i]=6;
            }
            sum+=(i+1)*a[i];
            if(!a[i]) cnt++;
        }
        if(cnt==6) break;
        if(sum%2==1){
            printf("Collection #%d:\nCan't be divided.\n\n",cas++);
            continue;
        }
        sum>>=1;
        for(int i=1;i<=6;i++){
            if(a[i-1]==0) continue;
            for(int j=0;j<=sum;j++){
                for(int k=0;k<=a[i-1]&&k*i+j<=sum;k++){
                    c2[k*i+j]+=c1[j];               //合并同类项
                }
            }
            for(int j=0;j<=sum;j++){
                c1[j]=c2[j];
                c2[j]=0;
            }
        }
        printf("Collection #%d:\n",cas++);
        if(c1[sum]) printf("Can be divided.\n\n");
        else printf("Can't be divided.\n\n");
    }

	return 0;
}


猜你喜欢

转载自blog.csdn.net/AgoniAngel/article/details/51900775