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;
}