题目背景
奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对N 头奶牛进行
了面试,确定了每头奶牛的智商和情商。
题目描述
贝西有权选择让哪些奶牛参加展览。由于负的智商或情商会造成负面效果,所以贝西不希望出展奶牛的智商之和小于零,或情商之和小于零。满足这两个条件下,她希望出展奶牛的智商与情商之和越大越好,请帮助贝西求出这个最大值。
输入输出格式
输入格式:• 第一行:单个整数N,1 ≤ N ≤ 400
• 第二行到第N + 1 行:第i + 1 行有两个整数:Si 和Fi,表示第i 头奶牛的智商和情商,−1000 ≤ Si; Fi ≤ 1000
输出格式:输出格式
• 单个整数:表示情商与智商和的最大值。贝西可以不让任何奶牛参加展览,如果这样做是最好的,输出0
输入输出样例
输入样例#1:
5 -5 7 8 -6 6 -3 2 1 -8 -5
输出样例#1:
8
说明
选择第一头,第三头,第四头奶牛,智商和为−5+6+2 = 3,情商和为7−3+1 = 5。再加
入第二号奶牛可使总和提升到10,不过由于情商和变成负的了,所以是不允许的
分析
特殊的0-1背包。常见的想法就是设 f(i, j) 表示 i, j 能否到达,对这道题来说数据太大,会超时、超空间,因为其实根本就没有这么多状态,很多状态都是无效的。但是,数组的下标和值都可以存储信息,所以我们可以把智商和情商分别存到到下标和值上,这样就完美解决了空间的问题,也算是一种状压 DP。
最后要注意:C++ 中没有负数下标,所以我们需要把 dp 数组平移 M 位。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 const int N = 405,M = 400000; 7 int f[M*2+100]; //f下标存iq,值存eq; 8 int iq[N],eq[N]; 9 int n,ans; 10 11 int main() 12 { 13 scanf("%d",&n); 14 for (int i=1; i<=n; ++i) 15 scanf("%d%d",&iq[i],&eq[i]); 16 memset(f,-0x3f,sizeof(f)); 17 f[M] = 0; 18 for (int i=1; i<=n; ++i) 19 { 20 if(iq[i] > 0) //根据iq[i]的符号确定循环方向,消除后效性 21 for (int j=M*2; j>=iq[i]; --j) 22 f[j] = max(f[j],f[j-iq[i]]+eq[i]); 23 else 24 for (int j=0; j<=M*2+iq[i]; ++j) 25 f[j] = max(f[j],f[j-iq[i]]+eq[i]); 26 } 27 for (int i=1; i<=M; ++i) 28 if(f[i+M] >= 0) 29 ans = max(ans,f[i+M]+i); //i是智商,f[i+M]情商 30 printf("%d",ans); 31 return 0; 32 }