您的位置:首页 > 其它

POJ 1014 Dividing ( 多重背包)

2013-08-27 16:06 225 查看
题意:玛莎和比尔有一批大理石(或弹珠)。他们想要将这批大理石分成价值和相等的两批。如果所有的大理石有同样的价值,那很简单,因为只要按数目分一半就行了。但是很可惜,一些大理石大一点,或者更漂亮一点。所以玛莎和比尔对每一个大理石分配一定的价值分从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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: