POJ - 2184 Cow Exhibition(01背包)

题目

题目意思就是要求出smartness和funness之和的最大值,同时这两个分别也大于或等于零。

一个变形的01背包问题。这个题目纠结了很久,翻了挺多博客,看完都是一知半解,后来看到了一个代码很清晰的博客,才慢慢理解大概是怎么解的。

下面是我对这个代码的理解,可以结合代码来看一下。

    先开一个很大的数组,一分为二,左边的一半存负数的情况,右边的一半存正数的情况,取中间值shift,假设其在这个“轴”上的坐标是0。这个数组是当s[i]为数组上的某个值时,f[i]该怎么取能使和最大。如果s[i]是负数的话,负数在数轴上是越往左边越小,所以应该从最大,也就是最右边开始往左推,此处最大应该是从0开始,(背包问题的常见思路,从最大的结果开始,检验这个结果能否成立),如果是正数则反过来,从最右边开始往左推,此处最大依据情况而定。这样遍历一次就能得到一个数组dp,这个dp的下标代表的是s[i],存的值就是f[i]的值。然后定义一个变量ans,初始化为0,,从0开始(s[i]>=0)遍历数组dp,如果对应存的值非负数(f[i]>=0),则ans取max(ans,i+dp[i+shift]),+shift从数轴的0开始往右遍历的意思。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=105;
const int maxs=200000;
const int shift=100000;
#define inf 100000000
int s[maxn],f[maxn],dp[maxs];

int main()
{
    ios::sync_with_stdio(false);
    int n,l,r,step,begin,end;
    while(cin>>n)
    {
        for(int i=0;i<n;i++)
            cin>>s[i]>>f[i];
        for(int i=0;i<maxs;i++)
            dp[i]=-inf;
        dp[0+shift]=0;
        l=r=0;
        for(int i=0;i<n;i++)
        {
            l=min(l,l+s[i]);
            r=max(r,r+s[i]);
            step=1;
            begin=l,end=r;
            if(s[i]>0)
            {
                step=-1;
                swap(begin,end);
            }
            for(int j=begin;j!=end+step;j+=step)
                dp[j+shift]=max(dp[j+shift-s[i]]+f[i],dp[j+shift]);
        }
        int ans=0;
        for(int i=0;i<=r;i++)
            if(dp[i+shift]>=0)
                ans=max(ans,i+dp[i+shift]);
        cout<<ans<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值