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
代码:
点击查看代码
#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);
}

浙公网安备 33010602011771号