这道题就得要讲到二进制优化算法了,对于1,2,4,8,......,2^n,......2的每一阶的数都能由它其中的某几阶数的和来表示——前文
1 0 1 2 0 0 1 0 0 0 1 1 0 0 0 0 0 0Sample Output
Collection #1: Can't be divided. Collection #2: Can be divided.
对于题目给的例子,永远是偏小的,他们可以用各种超时的方式写出来,当然AC永远是不会让你AC的。
思路:题目告诉了我们价值分别为1~6的石头一个他们的数量,我们要做的就是判断它们能否被等额平分。我们来思考这样一个问题,假如有22块价值为1的石头,我们将它们分成2的阶的和,会留下些什么?22=2+4+16,不会留下东西。那么再换个例子(这可不是我没有深思熟虑的结果,只是在举例子而已)32怎么说?32=1+2+4+8+16+1!它多出了1。那么如果用的是“<=”岂不是可以避免这类情况?但是那就会出现一种多拿的情况,那不就很尴尬了吗?
所以,我们对1~6每个石头,我们可以将它们的数量用二的阶乘的和来表示,这就是二进制优化的由来了。
但是上述的想法和接下来的代码都仅是使用于这道题的,二进制优化的实例为,对于10,可以有1,2,4,8组成,10=2+8,但是这样是不行的,这会让我们多拿些东西,譬如当上述成员存在时,我们有可能背包里放的是1+2+8的东西,这么就很尴尬了。所以我们要记录已经放了的东西,让K*2小于等于数量才是正解,对于多处的数我们用一个a[i]-x存储下来就行了,例如10可以有1,2,4和3存储一样。
二进制优化代码:
int cnt=0;
for(int i=1; i<=6; i++)
{
int k=1;
int x=0;
while(k<a[i])
{
b[cnt++]=k*i;
x+=k;
k*=2;
}
if(a[i]>x)
{
b[cnt++]=(a[i]-x)*i;
}
}
完整代码:
#include
#include
#include
using namespace std;
int a[7];
int b[50000];
int dp[500000];
int main()
{
int Case=0;
while(scanf("%d %d %d %d %d %d",&a[1],&a[2],&a[3],&a[4],&a[5],&a[6])!=EOF)
{
Case++;
if(Case>1)cout<x)
{
b[cnt++]=(a[i]-x)*i;
}
}
dp[0]=1;
for(int i=0; i=b[i]; j--)
{
if(dp[j-b[i]]) dp[j]=1;
}
}
if(dp[mid]) printf("Can be divided.\n");
else printf("Can't be divided.\n");
}
return 0;
}