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.
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.
The last line of the input file will be ``0 0 0 0 0 0''; do not process this line.
Output a blank line after each test case.
1 0 1 2 0 0 1 0 0 0 1 1 0 0 0 0 0 0
Collection #1: Can't be divided. Collection #2: Can be divided.
【题解】
大致题意:
有6种物品,每种物品的价值分别为1~6,现在输入每种物品的个数,问能不能把这些物品分为等价的两部分。
分析:
每件物品不一样,能不能刚好分为总价值的一半,明显的多重背包问题,其特点就是物品数>=1, 所以现在就套用多重背包模板。
递归的查找能满足条件的分类方式,如果找到就返回true,否则返回false,还有,既然是分两堆,那么如果总价值为奇数,就可以直接判定不可分了,
还有这道题比较卡剪枝,所以要适当剪枝,否则会TLE,具体见代码行注释。
【AC代码】
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int a[10];
int sum;
bool flag;
bool dfs(int mid,int sum,int i)//这里mid是总价值的一半 sum是当前总价值 i表示当前选到价值为i的物品
{
if(flag) return flag; //可以分为两半
if(mid == sum) //可以分为两半
{
flag=true;
return flag;
}
for(int j=i;j>=1;--j)//从当前价值开始遍历
{
if(a[j]) //如果价值为i的物品还有剩余
{
if(sum+j<=mid) //总价值还少于mid
{
a[j]--;//物品数减1
dfs(mid,sum+j,j); //继续寻找
if(flag) //这里相当于一个小小的剪枝, 能稍微提高一点效率
break;
}
}
}
return flag;
}
int main()
{
int n,p,cnt=1;
while(1)
{
p=0;
sum=0;
for(int i=1;i<=6;++i)
{
scanf("%d",&a[i]);
if(a[i]) p=1;
sum+=a[i]*i; //总价值
}
if(p==0) break; //如果输入全为0
printf("Collection #%d:\n",cnt++);
if(sum&1) //如果总数为奇数 直接判定不可分
{
printf("Can't be divided.\n\n");
continue;
}
sum/=2;
flag=false;//预置为false
bool tag=dfs(sum,0,6);
if(tag) printf("Can be divided.\n");
else printf("Can't be divided.\n");
printf("\n");
}
return 0;
}