洛谷 P2340 [USACO03FALL]Cow Exhibition G 题解

题目链接

1.题外话

咕咕咕

2.解题意

咕咕咕,比较容易理解,智商情商需要捆绑在一起。

3.找思路

每一个奶牛都只包含两种情况:选, 不选。并且很明显这不是一个完全背包。

考虑套一套01背包的板子:每个奶牛都有两个参数:智商,情商。在01背包板子中,每一个物品都有两个参数:体积,价值。

于是,第一种做法也就浮现而出:把智商设为体积,把情商当做价值,跑01背包。跑完后枚举一下智商大小,加上当前智商状态值所对应的的最大情商,取max即可。

按理说是可以过的。但是偏偏有几个奶牛不是智商捉急负数,就是情商要命负数,再不就是歪比哇卜双负数

对于智商为负数的情况,众所周知数组下标不能有负数,于是我们可以将数组往右平移一整个范围。这样保证即使智商全取负数中的最小值,也依然>=0。具体表现在代码中,就是数组多开一倍,枚举智商值的j增大一倍即可。

j对于情商为负数的情况。由于一维的01背包是从大到小枚举以保证每个物品只选一次。如果是负数,那么减去负数得正数,你将获得从小往大里枚举的效果(完全背包)。每个牛牛是独一无二的所以我们不能多次枚举,很明显不符合题意。

解决方法是遇到负数,你人为的把枚举的顺序倒过来即可。目的是保证每一个牛仅被选一次。,注意一下枚举智商的j的范围。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define N 407
using namespace std;
inline int read()
{
    int ans=0;
    char ch=getchar(),last=' ';
    while(ch>'9'||ch<'0')last=ch,ch=getchar();
    while(ch>='0'&&ch<='9')ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
    return last=='-'?-ans:ans;
}
struct cow{
    int iq,eq;
}cow[N];
int n,f[800007],maxn;
int main(){
    scanf("%d",&n);
    memset(f,-0x3f,sizeof(f));
    f[400000]=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&cow[i].iq,&cow[i].eq);
    }
    for(int i=1;i<=n;i++)
    {
        if(cow[i].iq>=0)
        {
            for(int j=800000;j>=cow[i].iq;j--)
                f[j]=max(f[j],f[j-cow[i].iq]+cow[i].eq);
        }
        else
        {
            for(int j=0;j<=800000+cow[i].iq;j++)
                f[j]=max(f[j],f[j-cow[i].iq]+cow[i].eq);
        }
    }
    for(int i=400000;i<=800000;i++)
    {
        if(f[i]>=0)
        maxn=max(maxn,f[i]+i-400000);
    }
    printf("%d",maxn);
}

完结撒花。

祝各位NOIP2020 RP++

原文地址:https://www.cnblogs.com/lbssxz/p/13644030.html