POJ 2184 Cow Exhibition ( 01背包变形 )

来源:互联网 发布:玻璃软件 编辑:程序博客网 时间:2024/05/21 12:39

题意:

牛类想要向世人证明他们聪明又幽默。经过测试,每头牛都有一个幽默度Fi和智商Si,现要求从N头牛中选择若干头牛去参加比赛,假设这若干头牛的智商之和为sumS,幽默度之和为sumF.现要求在所有选择中,在使得sumS>=0&&sumF>=0的基础上,使得sumS+sumF最大并输出其值.

 

分析:

01背包dp之后把符合要求的最优解统计出来。但是在解01背包的时候遇到一个问题是体积有负数,这样在dp的过程中会遇到两个问题:循环的时候超出体积的范围;

压缩空间的时候状态转移方程:dp[v]=max(dp[v],dp[v-c[i]]+w[i]),c[i]为负数时v-c[i]>v,这样按一般的循环的方向从大到下会重复计算。

先看第二个问题,在一般的01背包压缩空间的时候,体积的遍历是从大到小,因为dp[v]=max(dp[v],dp[v-c[i]]+w[i]),当前的dp[v]只取决于比自己小的dp[v-c[i]],所以从大到小遍历时每次dp[v-c[i]]和dp[v]都是上一次的状态。

如果体积为负v-c[i]>v,从大到小遍历dp[v-c[i]]是当前物品的状态,不是上一个,这样就会出错,解决的办法是从小到大遍历。

针对第一个问题,在处理的时候将整个数轴平移,使得原来所有可能的情况都为正。

例如这题,首先计算出数据的范围:

一共100组数,从-1000到1000,那么体积的范围就是-100*1000到100*1000。平移之后我们要处理的数据范围就在0到200000,新的原点变成100000。


#include <limits.h>#define V 200*1010#define N 105#define max(a,b) ((a)>(b)?(a):(b))int cost[N] ;int value[N] ;int dp[V+5] ;void DP_Solve ( int const n ) ;void Init_DP ( ) ; intmain ( ){    int n ;    scanf ("%d" , & n ) ;    int i ;    for ( i = 1 ; i <= n ; i ++ )    {        scanf ("%d%d" , & cost[i] , & value[i] ) ;    }    Init_DP ( ) ;    DP_Solve ( n ) ;    return 0 ;}void Init_DP ( ){    int i ;    for ( i = 0 ; i <= V ; i ++ )    {        dp[i] = INT_MIN ;    }    dp[100*1000] = 0 ;}  void DP_Solve ( int const n ){    int i ;    for ( i = 1 ; i <= n ; i ++ )    {        if ( cost[i] > 0 )        {            int j ;            for ( j = V ; j >= cost[i] ; j -- )            {                if ( dp[j-cost[i]] > INT_MIN )                {                   dp[j] = max ( dp[j] , dp[j-cost[i]] + value[i] ) ;                }            }        }        else        {            int j ;            for ( j = cost[i] ; j - cost[i] < V  ; j ++ )            {                if ( dp[j-cost[i]] > INT_MIN )                {                   dp[j] = max ( dp[j] , dp[j-cost[i]] + value[i] ) ;                }            }        }    }    int m_max ;    m_max = 0 ;    for ( i = 100 * 1000 ; i <= V ; i ++ )    {      if ( dp[i] >= 0 )             //注意不能写成 if (dp[i]) 会导致INT_MIN + i - 100 * 1000 溢出      {          m_max = max ( m_max , dp[i] + i - 100 * 1000 ) ;      }    }    printf ("%dn" , m_max ) ;}


 

原创粉丝点击