题目链接:hdu1059
题目大意:分别给出6种不同质量石头的数量 质量分别分1,2,3,4,5,6;问能否均分
题目思路:如果用普通的多重背包 他会超时
这时需要我们队多重背包进行二进制的优化
—
转化为
01
背包求解:把第
i
种物品换成
n[
i
]
件
01
背包中的物品,则得到了物品数为
Σn
[
i
]
的
01
背包问题
—
当然这样直接求解的复杂度仍然是
O(V*
Σn
[
i
])
。
—
我们考虑把第
i
种物品换成若干件物品,使得原问题中第
i
种物品可取的每种策略
——
取
0..n[
i
]
件
——
均能等价于取若干件代换以后的物品。另外,取超过
n[
i
]
件的策略必不能出现。
—
方法是:将第
i
种物品分成若干件物品,其中每件物品有一个系数,这件物品的费用和价值均是原来的费用和价值乘以这个系数。使这些系数分别为
1,2,4,...,2^(k-1),n[
i
]-2^k+1
,且
k
是满足
n[
i
]-2^k+1>0
的最大整数
。例如,如果
n[
i
]
为
13
,就将这种物品分成系数分别为
1,2,4,6
的四件物品。
—
将
n[
i
]
拆成
1,2,4,...,2^(k-1),n[
i
]-2^k+1
,(
k
是满足
n[
i
]-2^k+1>0
的最大整数)道理何在?
—
1
)
1+2+4+...+2^(k-1)+n[
i
]-2^k+1= n[
i
]
这就保证了最多为
n[
i
]
个物品
—
2
)
1,2,4,……,2^(k-1),
可以凑出
1
到
2^k –1
的所有整数(联系一个数的二进制拆分即可证明)
—
3
)
2^k
……
n[
i
]
的所有整数可以用若干个上述元素凑出(可以理解为凑
n[
i
]-t,
而
n[
i
]
为上面所有数的和,
t
则是一个小于
2^k
的数,那么在所有的数中去掉组成
2^k
的那些数剩下的就可以组成
n[
i
]-t
了)
复杂度为O(V*Σlog n[i])
很圆满的解决了问题#include<stdio.h>
#include<string.h>
#define max(a,b) a>b?a:b
int Va[100],n[7],dp[200000];
int main(){
int c=0;
while(~scanf("%d%d%d%d%d%d",&n[1],&n[2],&n[3],&n[4],&n[5],&n[6]))
{
if(n[1]==0&&n[2]==0&&n[3]==0&&n[4]==0&&n[5]==0&&n[6]==0)break;
printf("Collection #%d:\n",++c);
int i,j,sum=0,mid;
for(i=1;i<=6;i++)sum+=i*n[i];
if(sum%2){//如果奇数的话 不用分 直接输出不能够均分
printf("Can't be divided.\n\n");
continue;
}
else mid=sum/2;
memset(dp,0,sizeof(dp));
int count=0,temp;
for(i=1;i<=6;i++){
temp=1;
while(n[i]>=temp){
Va[++count]=i*temp;//每个新的分配而成的物品的重量
n[i]-=temp;
temp*=2;
}
if(n[i]>0){
Va[++count]=i*n[i];
}
}
dp[0]=1;
for(i=1;i<=count;i++){
for(j=mid;j>=Va[i];j--){
if(dp[j-Va[i]]){
dp[j]=1;
}
}
}
if(dp[mid]>0)printf("Can be divided.\n\n");
else printf("Can't be divided.\n\n");
}
return 0;
}