代码改变世界

HDU--1059 Dividing(多重背包)

2013-12-04 11:28  gongti  阅读(150)  评论(0编辑  收藏  举报
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1059
分析:有一堆石头2个人按照其价值均分,石头的价值分为六个等级1,2,3,4,5,6 
每一个等级有n[i]个石头也可能一个石头也没有。于是两个人按照总价值进行均分。
因为每一个等级的石头个数是不等的n[i],这是一个多重背包的问题。可以将背包的容量
看成是一个总价值的二分之一。并且要求装满。
#include<stdio.h>

const int INF=0XFFFFFF;

int V,dp[120005];

//01背包
void ZeroOnePack(int cost,int weight)
{
  for(int i=V;i>=cost;i--)
    dp[i]=dp[i]>dp[i-cost]+weight?dp[i]:dp[i-cost]+weight;
}
//完全背包
void CompletePack(int cost,int weight)
{
  for(int i=cost;i<=V;i++)
    dp[i]=dp[i]>dp[i-cost]+weight?dp[i]:dp[i-cost]+weight;
}
//多种背包
void MultiplePack(int cost,int weight,int amount)
{
  if(cost*amount>=V)
  {
    CompletePack(cost,weight);
    return;
  }
  int k=1;
  while (k<=amount)
  {
    ZeroOnePack(k*cost,k*weight);
    amount-=k;
    k*=2;
  }
  ZeroOnePack(amount*cost,amount*weight);
}

int main()
{
  int n[7],sum,k=1;;
  while (1)
  {
    sum=0;
    for(int i=1;i<=6;i++)
    {
        scanf("%d",&n[i]);
        sum+=i*n[i];
    }
    if(!n[1]&&!n[2]&&!n[3]&&!n[4]&&!n[5]&&!n[6]) break;

    printf("Collection #%d:\n",k++);
    //总价值必须是偶数,否则无法均分
    if(sum&1) printf("Can't be divided.\n\n");
    else
    {
      //初始化
      V=sum/2;
      for(int i=0;i<=V;i++)
        dp[i]=-INF;
      dp[0]=0;

      //多重背包
      for(int i=1;i<=6;i++)
        MultiplePack(i,i,n[i]);

      if(dp[V]>0)
         printf("Can be divided.\n\n");
      else
         printf("Can't be divided.\n\n");
    }
  }
  return 0;
}