这道刚开始都没想出来。。。
后来发现我以前做了一道和这个完全一样的题,就是计蒜客的平分娃娃,好菜呀(T_T)
题意:略
分析:
说的可能有些繁琐。。。大佬可以忽略,直接看代码
一道经典的多重背包问题,但是会卡时间,用二进制优化一下就解决了。
这里重点讲思路,题目问的如何将一堆弹珠均等对半分,可以先这样想,一个弹珠价值6,它的体积也是6,另一个弹珠的价值是5,那体积就是5,一个弹珠的价值就等于它的体积。
假设一堆弹珠的总价值是 x ,现在我们要找出一堆总价值为 x/2 的弹珠,那这堆一半总价值的弹珠的体积就是 x/2 ,那我们只要保证能在容量为 x/2 的背包中装下最大的价值(也就是x/2)也就代表弹珠可以对半分了,因此也就转化为一个完全背包问题了。
ac代码
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int a[7],dp[60001],v[100];//dp[n]表示为容量n的情况下,最大的价值,v[n]表示为第n个物品的容量值,同时也是第n个物品的价值
int main()
{
int cnt=0;
while(scanf("%d%d%d%d%d%d",a+1,a+2,a+3,a+4,a+5,a+6)&&(a[1]|a[2]|a[3]|a[4]|a[5]|a[6])&&++cnt){
memset(dp,0,sizeof(dp));
int ct=1,sum=0,f=0;
for(int i=1;i<7;++i){
sum+=i*a[i];
for(int j=1;j<=a[i];j<<=1){//二进制优化 13可以表示为 1,2,4,6 这4个数可以表示1-13内的任何数
// cout<<j<<endl;
v[ct++]=j*i;
// cout<<j*i<<" ";
a[i]-=j;
}
if(a[i])v[ct++]=a[i]*i;
}
// cout<<ct<<endl;
if(!(sum&1)){
sum/=2;
for(int i=1;i<ct;++i){//01背包问题
for(int j=sum;j>=v[i];--j){
dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
// cout<<dp[j]<<" ";
}
}
if(dp[sum]==sum)f=1;
}
if(f)printf("Collection #%d:\nCan be divided.\n\n",cnt);
else printf("Collection #%d:\nCan't be divided.\n\n",cnt);
}
return 0;