题目大意:
就是给你价值为1、2、3、4、5、6的硬币的个数,然后让你判断能否把他们分成价值相等的两部分。
三种写法,前两种都是多重背包的二进制优化写法时间700ms左右
第三种为dfs写法 时间 50ms以下
方法一:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int dp[555555];
int c;
int value[155555],sizes[155555];//分解后价值以及体积
int main()
{
int no=0;
while(++no)
{
memset(dp,0,sizeof(dp));
int sum=0;
int counts=0;
for(int i=1;i<=6;i++)
{
scanf("%d",&c);
sum+=c*i;
for(int j=1;j<=c;j<<=1)
{
value[counts]=j*i;
sizes[counts]=j*i;
counts++;
c-=j;
}
if(c>0)
{
value[counts]=c*i;
sizes[counts]=c*i;
counts++;
}
}
if(sum==0)
break;
printf("Collection #%d:\n",no);
if(sum%2)
{
printf("Can't be divided.\n\n");
continue;
}
sum/=2;
for(int i=0;i<counts;i++)
{
for(int j=sum;j>=sizes[i];j--)
{
dp[j]=max(dp[j],dp[j-sizes[i]]+value[i]);
}
}
//printf("%d %d\n",sum,dp[sum]);
if(dp[sum]==sum)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}
方法二:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int dp[555555];
int w[8],v[8],c[8];
void ZeroOne_Pack(int cost,int value,int n)
{
for(int i=n;i>=cost;i--)
{
dp[i]=max(dp[i],dp[i-cost]+value);
}
}
void Complete_Pack(int cost,int value,int n)
{
for(int i=cost;i<=n;i++)
{
dp[i]=max(dp[i],dp[i-cost]+value);
}
}
int main()
{
int no=0;
while(++no)
{
memset(dp,0,sizeof(dp));
int sum=0;
for(int i=1;i<=6;i++)
{
scanf("%d",&c[i]);
sum+=c[i]*i;
w[i]=v[i]=i;
}
if(sum==0)
break;
printf("Collection #%d:\n",no);
if(sum%2)
{
printf("Can't be divided.\n\n");
continue;
}
sum/=2;
for(int i=1;i<=6;i++)
{
if(c[i]*w[i]>sum)
{
Complete_Pack(w[i],v[i],sum);
}
else
{
int k=1;
while(k<c[i])
{
ZeroOne_Pack(k*w[i],k*v[i],sum);
c[i]-=k;
k<<=1;
}
ZeroOne_Pack(c[i]*w[i],c[i]*v[i],sum);
}
}
if(dp[sum]==sum)
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}
方法三:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int c[8];
int dfs(int val,int num)
{
if(num<=0)
return 0;
if(val==0)
return 1;
while(c[num]==0||val<num)//如果没有了或者单个重量比背包容量大则跳过
num--;
c[num]--;//拿走一个
return (dfs(val-num,num)||dfs(val,num-1));
}
int main()
{
int no=0;
while(++no)
{
int sum=0;
for(int i=1;i<=6;i++)
{
scanf("%d",&c[i]);
sum+=c[i]*i;
}
if(sum==0)
break;
printf("Collection #%d:\n",no);
if(sum%2)
{
printf("Can't be divided.\n\n");
continue;
}
sum/=2;
if(dfs(sum,6))
printf("Can be divided.\n\n");
else
printf("Can't be divided.\n\n");
}
return 0;
}