POJ 2184 Cow Exhibition(DP:01背包)

273 篇文章 0 订阅
112 篇文章 0 订阅

POJ 2184 Cow Exhibition(DP:01背包)

http://poj.org/problem?id=2184

题目:每头牛有一个S值和F值,现在要求你在N头牛里面选牛,使得被选牛的S值总和SS ,加上F值总和FF,即SS+FF最大.并且SS>=0且FF>=0.问你那个最大值是多少?

分析:二维价值最大问题转化为一维价值最大问题.

现在暂且加上所有S值都为正数,那么我们令dp[i][s]=x表示处理完前i个牛后,当前被选的牛S值和为s时,其F值总和最大为x.

dp[i][s]= max( dp[i-1][s] , dp[i-1][s-Si]+Fi ),s>=Si,则当求完所有的dp[n][j]之后, 0<=j<=SS. 就可以在这些dp[n][j]=x中选出j+x最大的那个值.

       现在的问题是S的值有可能为负,这里就要注意了:

假设s=100,Si=10,那么dp[i][100]= max( dp[i-1][100] , dp[i-1][90]+Fi ),所以s依然可以从MAXN循环到10从而更新一维dp的.此时是大值依赖小值.应是s值从大到小更新.

假设s=100,Si=-10,那么dp[i][100]= max( dp[i-1][s] , dp[i-1][100+10]+Fi ),所以此时dp[i-1][110]可能越界,不能这么算了. 所以s应该从小值0循环到MAXN-10,才对.此时是小值依赖大值.应使s值从小到大更新.

       又因为Si的和取值范围是[-10W,10W]之间,所以这个需要用一条宏语句解决:#define dp(a) dp[a+100000]   即可.

dp(-20) 映射到了dp[10W-20]上.

初始:除了dp(0)=0外,其他所有dp(i)=-100W,i输入[-10W,10W]内.

AC代码:172ms

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXW = 200000 + 1000;
const int INF = 1000000;
#define dp(i) dp[(i)+100000]
int nKind, dp[MAXW];
int weight[1010],value[1010];
void ZeroOnePack()
{
    for(int i = 1; i <= nKind; i++)
        if(weight[i] >= 0)
        {
            for(int j = 100000; j - weight[i] >= -100000; j--)
                if(dp(j - weight[i]) != -INF)//有效值
                    dp(j) = max(dp(j) , dp(j - weight[i]) + value[i]);
        }
        else
        {
            for(int j = -100000; j - weight[i] <= 100000; j++)
                if(dp(j - weight[i]) != -INF)
                    dp(j) = max(dp(j) , dp(j - weight[i]) + value[i]);
        }
}
int main()
{
    while(scanf("%d",&nKind)==1)
    {
        for(int i=1;i<=nKind;i++)
        {
            scanf("%d%d",&weight[i],&value[i]);
        }
        for(int i=-100000;i<=100000;i++) dp(i)=-INF;
        dp(0)=0;
        ZeroOnePack();
        int sum=0;
        for(int i=0;i<=100000;i++)
        {
            if(dp(i)>=0 && i+dp(i)>sum)
                sum = i+dp(i);
        }
        printf("%d\n",sum);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值