POJ 1014 Dividing ( 多重背包)

7 篇文章 0 订阅
题意:玛莎和比尔有一批大理石(或弹珠)。他们想要将这批大理石分成价值和相等的两批。如果所有的大理石有同样的价值,那很简单,因为只要按数目分一半就行了。但是很可惜,一些大理石大一点,或者更漂亮一点。所以玛莎和比尔对每一个大理石分配一定的价值分从1到6。现在他们要分离这些大理石使得分别能获得相同总值。很可惜,他们意识到有时不可能平分大理石(即使总值是偶数)。例如,如果有1个价值为1,1个价值为3,两个价值为4的大理石,这样他们不可能被平分,因此,他们请求你来写一个程序来判断是否能平分。

分析: 
如果想要公平的分得弹球,那么弹球的价值总和一定是偶数,可以先进行判断弹球的价值总和,若是奇数则不需要做下面的判断。
如果是偶数,我们可以把这个问题映射为多重背包问题,并且这个背包是要求完全装满的。背包的总容量V就是所有弹球总价值和sum的一半,弹球的cost和weight都是其编号。个数则是由外界输入的。最后进行判断:如果得到的F[V]确定的等于sum/2,则说明能够公平的分弹球。需要注意的是,由于弹球最大个数是20000,所以极端情况是20000个弹球都是放在了价值为6的位置上


//  380K    16MS
#include <stdio.h>
#define MAX 60005
#define max(a,b) ((a)>(b)?(a):(b))
int dp[MAX] ;
int V ;
int num[7] ;

void ZeroOnePack ( int const cost , int const value )
{
    int i ;
    for ( i = V ; i >= cost ; i -- )
    {
        dp[i] = max( dp[i] , dp[i-cost] + value ) ;
    }
}

void CompletePack ( int const cost , int const value )
{
    int i ;
    for ( i = cost ; i <= V ; i ++ )
    {
        dp[i] = max ( dp[i] , dp[i-cost] + value ) ;
    }
}

void MultiplePack ( int const cost , int const value , int amount )
{
    if ( amount * cost > V  )
    {
        CompletePack ( cost , value ) ;
    }
    else
    {
        int k ;
        for ( k = 1 ; k < amount ; k *= 2 )
        {
            ZeroOnePack ( k * cost , k * value ) ;
            amount -= k ;
        }
        if ( amount )
        {
            ZeroOnePack ( amount * cost , amount * value ) ;
        }
    }
}

void Init_DP ( )
{
    int i ;
    for ( i = 1 ; i <= V ; i ++ )
    {
        dp[i] = 0 ;
    }
}

int
main ( )
{
    int count ;
    count = 1 ;
    while ( 1 )
    {
        int sum ;
        sum = 0 ;
        int i ;
        for ( i = 1 ; i <= 6 ; i ++ )
        {
            scanf ("%d" , & num[i] ) ;
            sum += i * num[i] ;
        }
        if ( !sum )
        {
            break ;
        }
        else
        {
            if ( sum % 2 )//不剪枝铁定WA
            {
               printf ("Collection #%d:\nCan't be divided.\n\n", count ) ;
            }
            else
            {
                V = sum/2 ;
                for ( i = 1 ; i <= 6 ; i ++ )
                {
                    MultiplePack ( i , i , num[i] ) ;
                }
                if ( dp[V] == V  )
                {
                    printf ("Collection #%d:\nCan be divided.\n\n" , count ) ;
                }
                else
                {
                    printf ("Collection #%d:\nCan't be divided.\n\n", count) ;
                }
            }
        }
        Init_DP ( ) ;
        count ++ ;
    }
    return 0 ;
}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值