传送门:点击打开链接
题目大意:给你6给价值分别是1到6的珠子的分别对应的数量。然后判断这些珠子是否能够分成价值相等的两部分。
解题思路:完全背包的思路,设dp[i]为花费上限为i的背包能分到的最大价值的珠子,则当dp[sum/2]的最大价值刚好能装满,即:dp[sum/2]==sum/2,即yes。
AC代码如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<string>
#include<math.h>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
int dp[maxn];
int max(int a,int b)
{
return a>b?a:b;
}
void pack01(int v,int h,int hmax)
{
for(int j=hmax;j>=h;j--)
dp[j]=max(dp[j],dp[j-h]+v);
return ;
}
void packall(int v,int h,int hmax)
{
for(int j=h;j<=hmax;j++)
dp[j]=max(dp[j],dp[j-h]+v);
return ;
}
void packs(int v,int h,int num,int hmax)
{
if(h*num>=hmax) //最大花费如果超过背包容量的话用完全背包
{
packall(v,h,hmax);
return ;
}
int k=1;
while(k<=num) //否则转化成每个物品用二进制优化成01背包
{
pack01(k*v,k*h,hmax);
num-=k;
k<<=1;
}
if(num)
pack01(num*v,num*h,hmax);
return ;
}
int main()
{
int i,sum,a[7],k,t=0;
while(1)
{
if(t)
cout<<endl;
k=sum=0;
for(i=1;i<=6;i++)
{
cin>>a[i];
k+=a[i];
sum+=i*a[i];
}
if(!k)
break;
printf("Collection #%d:\n",++t);
if(sum&1)
{
cout<<"Can't be divided."<<endl;
continue;
}
memset(dp,0,sizeof(dp));
sum/=2;
for(i=1;i<=6;i++)
packs(i,i,a[i],sum);
if(dp[sum]==sum)
cout<<"Can be divided."<<endl;
else
cout<<"Can't be divided."<<endl;
}
return 0;
}