HDU 1059 Dividing(多重背包二进制优化)

原题

题意:给你 6 个数,代表 1~6 的数的数量,问你是否能将这堆数分成两组,使他们各自和相等

思路:首先我们可以对整堆数求和,和为 sum ,如果和是奇数,则肯定不对;如果是偶数的话,就将问题转化成能否从这堆数中取若干数,使他们和为 sum/2 。那该问题其实就又转化为了一个容积为 sum/2 的多重背包问题了,如果 g[sum/2] == sum/2 就可以。

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<Vector>
#include<cstring>
#define pb push_back
using namespace std;
int g[500005],arr[10];
int main()
{
    int ans,sum=0,cnt=1;
    while(~scanf("%d%d%d%d%d%d",&arr[1],&arr[2],&arr[3],&arr[4],&arr[5],&arr[6]))
    {
        memset(g,0,sizeof(g));
        sum=0;
        for(int i=1; i<=6; i++)
        {
            sum+=i*arr[i];
        }
        if(!sum)
            break;
        printf("Collection #%d:\n",cnt++);
        vector<pair<int,int>>goods;
        for(int i=1; i<=6; i++)
        {
            {
                for(int k=1; k<=arr[i]; k*=2)
                {
                    arr[i]-=k;
                    goods.pb({i*k,i*k});
                }
                if(arr[i]>0)
                    goods.pb({i*arr[i],i*arr[i]});
            }
        }
        if(sum%2)
            printf("Can't be divided.\n\n");
        else
        {
            ans=sum/2;
            for(auto i:goods)
            {
                for(int j=ans; j>=i.first; j--)
                {
                    g[j]=max(g[j],g[j-i.first]+i.second);
                }
            }
            if(g[sum/2]==sum/2)
                printf("Can be divided.\n\n");
            else
                printf("Can't be divided.\n\n");
        }
    }
    return 0;
}
posted @ 2020-04-02 18:30  Pecoz  阅读(140)  评论(0编辑  收藏  举报