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.
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.
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
要注意,每组数据之间有一个换行
来,上代码:
View Code
#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: Can't be divided. ",now); continue; } sum_value/=2; if(Check_Answer()) printf("Collection #%d: Can be divided. ",now); else printf("Collection #%d: Can't be divided. ",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: Can't be divided. ",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: Can be divided. ",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: Can't be divided. ",now); } return 0; }