AC日记——Dividing poj 1014

Posted Only U - IU

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AC日记——Dividing poj 1014相关的知识,希望对你有一定的参考价值。

Dividing
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 69575   Accepted: 18138

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.

Source

 
题目大意:
  有很多很多的物品,但是总数不过20000。
  然后每个物品的价值在1~6之间
  很多组数据
  每组数据分别输出价值为1~6的物品的个数
  然后叫你判断是否能被分成价值为两堆的物品
 
思路:
  背包dp,难的一比、、
  这我提交了有4遍才过,两遍tle,一遍pre
  这题坑很多
  读完题后,很多人可能认为这是一道搜索题
  然后开始暴力搜索,最后tle成**。
  我们来分析一下这道题的解法
  首先,它要你把物品分成两堆,而且价值要相等
  所以,我们就有了一个优化
  当物品总价值%2==1时,判定为不能均分
  如果%2==0的话
  我们开始dp
  这个dp是一个裸的多重背包dp
  我们用当前物品的价值推所有价值的是否存在
  价值为i的物品当前层次由价值为i-1的物品当前层次推出
  然后判断物品总价值/2的价值是否存在就好了
  因为物品总价值/2能被凑出来,那么另一半肯定也能
  反之则不能
  但是有点坑
  如果你真的是这样顺着跑了下来,可能会超时
  所以我们要在dp的过程中判定是否有物品总价值/2存在
  这样的一个小优化就不会超时就能ac了
  感觉应该还有更好的解法,但是我想不出来了。、、。
  还有一点
  就是我的一遍pre
  要注意,每组数据之间有一个换行
 
来,上代码:
#include<cstdio>
#include<cstring>

using namespace std;

int a[7],sum_value=0,ci[7][20001],now=0;

bool dp[7][120000];

bool Check_Answer()
{
    memset(dp,false,sizeof(dp));
    dp[0][0]=true;
    for(int i=1;i<=6;i++)
    {
        for(int j=0;j<=sum_value;j++)
        {
            if(dp[i][sum_value]) return true;
            if(dp[i-1][j])
            {
                for(int v=0;v<=a[i];v++) dp[i][j+ci[i][v]]=true;
            }
        }
    }
    if(dp[6][sum_value]) return true;
    else return false;
}

int main()
{
    bool if_break;
    while(1)
    {
        if_break=true,sum_value=0,now++;
        for(int i=1;i<=6;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]) if_break=false;
            sum_value+=a[i]*i;
            for(int j=1;j<=a[i];j++) ci[i][j]=i*j;
        }
        if(if_break) break;
        if(sum_value%2)
        {
            printf("Collection #%d:\\nCan\'t be divided.\\n\\n",now);
            continue;
        }
        sum_value/=2;
        if(Check_Answer()) printf("Collection #%d:\\nCan be divided.\\n\\n",now);
        else printf("Collection #%d:\\nCan\'t be divided.\\n\\n",now);
    }
    return 0;
}

 

另附我的一个失败代码:

#include<cstdio>
#include<cstring>

using namespace std;

int a[7],sum_value,num,ci[20001],flag;

bool dp[70000];

int main()
{
    int now=0;
    while(1)
    {
        now++;
        memset(dp,false,sizeof(dp));
        sum_value=0,num=0,flag=1;
        bool if_break=true;
        for(int i=1;i<=6;i++)
        {
            scanf("%d",&a[i]);
            sum_value+=a[i]*i,num+=a[i];
            if(a[i]!=0)
            {
                if_break=false;
                for(int j=flag;j<flag+a[i];j++) ci[j]=i;
                flag+=a[i];
            }
        }
        if(if_break) break;
        if(sum_value%2)
        {
            printf("Collection #%d:\\nCan\'t be divided.\\n\\n",now);
            continue;
        }
        sum_value/=2;
        int max_now=0;
        dp[0]=true;
        for(int i=1;i<=num;i++)
        {
            int max_now_=max_now;
            for(int j=0;j<=max_now;j++)
            {
                if(dp[j])
                {
                    dp[j+ci[i]]=true;
                    if(j+ci[i]==sum_value)
                    {
                        printf("Collection #%d:\\nCan be divided.\\n\\n",now);
                        if_break=true;
                        break;
                    }
                    if(j+ci[i]>max_now_&&j+ci[i]<=sum_value) max_now_=j+ci[i];
                }
            }
            max_now=max_now_;
            if(if_break) break;
        }
        if(if_break) continue;
        printf("Collection #%d:\\nCan\'t be divided.\\n\\n",now);
    }
    return 0;
}
View Code

 

以上是关于AC日记——Dividing poj 1014的主要内容,如果未能解决你的问题,请参考以下文章

poj1014 Dividing (多重背包)

poj 1014 Dividing

POJ-1014 Dividing

多重背包,附上例题(POJ - 1014 Dividing)

POJ1014Dividing[多重背包可行性]

POJ 1014 Dividing(多重背包+二进制优化)