1;把每个石子的价值看做weight及cost,再抽象成dp模型,以便判断某个价值是否能通过组合得到
对多重背包的运算进行优化,采用二进制
2:对于给定价值和相应价值的数量,判断某个价值能否取到,或者取到离该价值最近的价值,一般采用多重背包
3:类似于hdu1059该题为判断某个价值能否取到,那么如果dp[i]=i,则可以取到,而对于poj1276要得到离i最近的那个价值,只需输出dp[i]即可,初始化全都为0,
还有另一种初始化方法,就是恰好取到(hdu1059)的题目全都初始化为inf,dp[0]=1,然后只需判断dp[i]是否大于0即可,对于(poj1276)则全都初始化为0
hdu2844为hdu1059的变相题目,只需要判断在小于总价值m的数中,dp[i]=i的个数
#include <iostream>
#include <cstdio>
#include <string.h>
using namespace std;
int f[80000],sum;
int max(int a,int b)
{
if (a>b)
return a;
else
return b;
}
void baggall(int cost,int weight)//完全背包
{
for (int i=cost;i<=sum;++i)
f[i]=max(f[i],f[i-cost]+weight);
}
void bagg01(int cost,int weight)//01背包
{
for (int i=sum;i>=cost;--i)
f[i]=max(f[i-cost]+weight,f[i]);
}
void fun(int cost,int weight,int num)
{
int k;
if (cost*num>=sum)//在价值总和大于sum值时,为完全背包
{
baggall(cost,weight);
return ;
}
k=1;
while(k<num)//注意此处的num值在变化,可通过证明说明这样可以取到任意值
{
bagg01(cost*k,weight*k);
num-=k;
k=2*k;//奇数可以通过1与偶数得到,所以k每次计算应该乘以2
}
bagg01(num*cost,num*weight);//比如num=13,则还有一个没有考虑(在循环体中),此处是考虑漏下的
}
int main()
{
int k=1,a[7],i;
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])
{
printf ("Collection #%d:\n",k++);
sum=1*a[1]+2*a[2]+3*a[3]+4*a[4]+5*a[5]+6*a[6];
if (sum%2==1)
{
printf ("Can't be divided.\n\n");
continue;
}
sum=sum/2;
memset(f,0,sizeof(f));
for (i=1;i<=6;++i)
if (a[i])
fun(i,i,a[i]);
if (f[sum]==sum)
printf ("Can be divided.\n\n");
else
printf ("Can't be divided.\n\n");
}
return 0;
}