题目背景
奶牛想证明它们是聪明而风趣的。为此,贝西筹备了一个奶牛博览会,她已经对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,不过由于情商和变成负的了,所以是不允许的
解析:由于这是每个奶牛装或不装,很明显这是一个01背包
状态:dp[i][j]=x表示考虑到1-i头奶牛,智商和为j的最大情商和为x
答案:max{dp[n][j](0<=j<=400000)}
转移:dp[i][j]=max(dp[i-1][j-IQ[i]]+EQ[i],dp[i-1][j])
初值:memset(dp,-999999,sizeof(dp))
dp[i][0]=1(0<=i<=n)
但是由于j有可能为负数,所以要将dp数组整体平移
由-400000-400000 变成0-800000
所以代码是这个样子的:
#include<bits/stdc++.h> using namespace std; int IQ[401],EQ[401]; int dp[401][800001]; int ans; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&IQ[i],&EQ[i]); } memset(dp,-999999,sizeof(dp)); for(int i=0;i<=n;i++) dp[i][400000]=0; for(int i=1;i<=n;i++) { for(int j=1;j<=800000;j++) { if(j>IQ[i]) { dp[i][j]=max(dp[i-1][j],dp[i-1][j-IQ[i]]+EQ[i]); } else { dp[i][j]=dp[i-1][j]; } } for(int j=1;j<=800000;j++) { dp[i-1][j]=dp[i][j]; } } for(int i=400000;i<=800000;i++) { if(dp[n][i]>=0) ans=max(ans,dp[n][i]+i-400000); } cout<<ans; return 0; }
但是你只要稍微测试一下就知道,这个代码会MLE。。。
下面来介绍一下我的解决方法:滚动数组!!!
这是指在第i项只与第i-1项有关系的一种dp优化方法,这可以将第i-2项之前省略,能节省空间。
数组滚动后的代码如下:
#include<bits/stdc++.h> using namespace std; int IQ[401],EQ[401]; int dp[3][800001]; int ans; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d",&IQ[i],&EQ[i]); } memset(dp,-999999,sizeof(dp)); dp[1][400000]=0; dp[2][400000]=0; for(int i=1;i<=n;i++) { for(int j=1;j<=800000;j++) { if(j>IQ[i]) { dp[2][j]=max(dp[1][j],dp[1][j-IQ[i]]+EQ[i]); } else { dp[2][j]=dp[1][j]; } } for(int j=1;j<=800000;j++) { dp[1][j]=dp[2][j]; } } for(int i=400000;i<=800000;i++) { if(dp[1][i]>=0) ans=max(ans,dp[1][i]+i-400000); } cout<<ans; return 0; }
完美解决
原文地址:https://www.cnblogs.com/chen-1/p/10886635.html