D.
题面如下:
有两个小朋友想要平分一大堆糖果,但他们不知道如何平分需要你的帮助,由于
没有spj我们只需回答能否平分即可。
糖果大小有6种分别是1、2、3、4、5、6,每种若干颗,现在需要知道能不能将
这些糖果分成等额的两堆。
一颗大小为6的糖果,可以相当于2颗大小为3的糖果,其他同理,即大小满足加
法,但是1颗糖果是不能被拆分的。
Input:
多组输入,每行输入6个非负整数,分别表示大小为1、2、3、4、5、6的糖果的
数量,若输入6个0代表输入结束。单种糖果的数量不会超过20000。
Output:
每组询问先输出一行 "Collection #k:",k表示第几组询问。再输出一行表示答案,
若能分割,输出 "Can be divided.",若不能输出 "Can't be divided."
每组输出后空一行
Sample Input: Sample Output:
1 0 1 2 0 0 Collection #1:
1 0 0 0 1 1 Can't be divided.
0 0 0 0 0 0
Collection #2:
Can be divided.
本题首先判断总大小(或看成总质量)的奇偶情况,很明显,为奇数时一定不能平分,而为偶数时只要只要判断背包达到总的一半即可,剩余的相加即为另一半。考虑到超时情况,先进行二进制优化简化计算量,再进行多重背包判断是否存在符合的状态。
代码实现:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define hhh 100005
int main(){
int j=0,flog,sum,l,t=1;
int a[hhh],b[hhh],dp[hhh];
while(t){ //使支持多组输入
sum=0;
for(int i=1;i<=6;i++){ //输入6种糖果的数量,求总大小sum
scanf("%d",&a[i]);
sum+=a[i]*i;
}
if(sum==0){ //即输入6个0代表输入结束,跳出循环
break;
}
else if(sum!=0){
j++;
printf("Collection #%d:\n",j); //据提意输出询问第几个
if(sum%2==1){ //若总大小为奇数,则一定不能评分
printf("Can't be divided.\n");
printf("\n"); //格式要求 每组输出后空一行
}
else{
l=0,flog=0;
for(int i=1;i<=6;i++){ //二进制优化 简化计算量
for(int s=1;s<=a[i];s=s*2){
l++;
b[l]=s*i;
a[i]=a[i]-s;
}
if(a[i]>0){ //使未简化的量存在
l++;
b[l]=a[i]*i;
}
}
memset(dp,0,sizeof(dp)); //dp数组初始化为0
for(int i=1;i<=l;i++){ //多重背包 判断dp是否存在一种状态等于sum/2
for(int s=sum/2;s>=b[i];s--){
dp[s]=max(dp[s],dp[s-b[i]]+b[i]);
if(dp[s]==sum/2){
flog=1; //若存在即可平分,标记
break; //存在,退出内层for
}
}
if(flog==1){
break; //存在,退出外层for
}
}
if(flog==1){
printf("Can be divided.\n");
}
else{
printf("Can't be divided.\n");
}
printf("\n"); //格式要求 每组输出后空一行
}
}
}
return 0;
}