Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 58921 | Accepted: 15200 |
Description
Input
The last line of the input file will be "0 0 0 0 0 0"; do not process this line.
Output
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
题目大意:
有六个大理石,他们的价值分别是1,2,3,4,5,6,然后分别给出六个大理石的个数,问如何平分给两个人,令两个人所得到的价值相等。
这里要求恰好达到平分这个状态,也就是当揹包大小是价值的一半恰好装满,所以dp的初始值是负无穷。开始以为数据小(没看清题),其实大的该死,我就用01揹包去做,果断超时。
所以就改成多重揹包改二进制优化的01揹包+完全揹包。就是个模板了。好像只要优化的01揹包也能过,不过不知道怎么做。
下面是模拟多重揹包问题,总共6个物品,将第i个物品的价值与费用都看做是i,这样套用揹包九讲的多重揹包模板就可以了,不过注意的是数组要开的大一点.
代码:16MS (这是codeblocks运行的代码)
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define M 100005
#define INF -99999;
int sum,v[7],dp[M];
void CompletePack(int cost,int wight)
{
int i;
for(i=cost;i<=sum;i++)
dp[i]=max(dp[i],dp[i-cost]+wight);
}
void ZeroOnePack(int cost,int wight)
{
int i;
for(i=sum;i>=cost;i--)
dp[i]=max(dp[i],dp[i-cost]+wight);
}
void MultiplePack(int cost,int wight,int amount)
{
if(cost*amount>=sum)
{
CompletePack(cost,wight);
return;
}
int k=1;
while(k<amount)
{
ZeroOnePack(k*cost,k*wight);
amount-=k;
k=k<<1;
}
ZeroOnePack(amount*cost,amount*wight);
}
void DP()
{
int i,j,k;
for(i=0;i<=sum;i++) dp[i]=i==0?0:INF;
for(i=1;i<=6;i++)
MultiplePack(i,i,v[i]);
}
int main()
{
int flag,i,t=0;
while(1)
{ t++;sum=0;
for(i=1;i<=6;i++)
{
cin>>v[i];
sum+=i*v[i];
}
if(!sum) break;
printf("Collection #%d:\n",t);
if(sum&1){
printf("Can't be divided.\n\n");
continue;
}
sum=sum>>1;
DP();
if(dp[sum]>=0)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}