AIGC标识 01背包二维-洛-Cow Exhibition G

P2340 [USACO03FALL] Cow Exhibition G

题目描述

奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对 \(N\) 头奶牛进行了面试,确定了每头奶牛的智商和情商。

贝西有权选择让哪些奶牛参加展览。由于负的智商或情商会造成负面效果,所以贝西不希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛的智商与情商之和越大越好,请帮助贝西求出这个最大值。

输入格式

第一行:单个整数 \(N\),\(1 \le N \le 400\)。

第二行到第 \(N+1\) 行:第 \(i+1\) 行有两个整数:\(S_i\) 和 \(F_i\),表示第 \(i\) 头奶牛的智商和情商,\(-1000 \le S_i,F_i \le 1000\)。

输出格式

输出单个整数:表示情商与智商和的最大值。贝西可以不让任何奶牛参加展览,如果这样做是最好的,输出 \(0\)。

输入输出样例 #1

输入 #1

5
-5 7
8 -6
6 -3
2 1
-8 -5

输出 #1

8

说明/提示

选择第一头,第三头,第四头奶牛,智商和为 \(−5+6+2 = 3\),情商和为 \(7−3+1 = 5\)。

再加入第二号奶牛可使总和提升到 \(10\),不过由于情商和变成负的了,所以是不允许的。

原来思路

每头牛选与不选,其要保存智商和情商俩个信息,二维01背包,但bool int dp[800010][800010]超内存,超时,改成int dp[800010]表示情商为 i+dw 时最大智商。但是nw = 3.210^8,担心TLE,就用set q存已存在的情商,这是就出问题了:dp[x + s[i]]中跟新了最大, x+s[i] 如果在q里已经存在,跟新到这里的时候可能在加一次。所以要倒着跟新,set要大到小存储。但是当s[i]小于0,还是会出现一头牛选多次的情况。
代码:

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n;
int s[410],f[410];
const int dw = 400000;
int ans = 0xcfcfcfcf;
int dp[800010];
set<int,greater<int>> q;
int main()
{
    cin>>n;
    for(int i = 1;i <= n;i++)    cin>>s[i]>>f[i];
    memset(dp,0xcf,sizeof(dp));
    q.insert(dw);    //初值要赋成0
    dp[dw] = 0;
    for(int i = 1;i <= n;i++)
    {
        vector<int>temp;
        for(auto x : q)
        {
            //cout<<x-dw<<endl;
            dp[x + s[i]] = max(dp[x + s[i]],dp[x] + f[i]);
            temp.push_back(x+s[i]);
        }
        for(auto x : temp)    q.insert(x);
    }
    for(int i = dw;i <= 800000;i++)
    {
        if(dp[i] >= 0)    ans = max(ans,i-dw+dp[i]);
    }
    cout<<(ans < 0 ? 0 : ans);
    return 0;
}

找到原因后

1.s[i]>0 时,反着遍历q;S[i]<0时,正着遍历q
2.优化背包范围,每个物品背包范围-i\(*\)w(最大)~ i\(*\)w(最大),但是对于s[i]<0,背包也要正着遍历

方案一代码

点击查看代码
for(int i = 1;i <= n;i++)
    {
        vector<int>temp;
        if(s[i] < 0)
        {
            for(auto x : q)
            {
                //cout<<x-dw<<endl;
                dp[x + s[i]] = max(dp[x + s[i]],dp[x] + f[i]);
                temp.push_back(x+s[i]);
            }
        }
        else 
        {
            // 反向遍历
            for(auto it = q.rbegin(); it != q.rend(); ++it) 
            {
                dp[*it + s[i]] = max(dp[*it + s[i]],dp[*it] + f[i]);
                temp.push_back(*it + s[i]);
            }  
        }
        for(auto x : temp)    q.insert(x);
    }
posted @ 2026-08-10 21:28  lucky_lh  阅读(4)  评论(0)    收藏  举报