题意:
有很多羊,每只羊有一个幽默度和智商,要选出一些羊,智商加幽默度总和最大,其中智商总和和幽默度总和都不能是负数。
样例输入:
5
-5 7
8 -6
6 -3
2 1
-8 -5
样例输出:
8
分析:
这很像一个01背包题,但是有两个价值,却没有重量
我们就把其中一个看成重量,另一个看成价值
答案就是max(i+dp[i])
那如何保证数据大于0呢?
我们可以把价值总体向右移100000个单位,然后设原点O为100000
之后就可以进行dp了
转移方程仍是:dp[j]=dp[j-w[i]]+v[i];
但要注意,如果w[i]>=0要逆向循环,w[i]<0要顺向循环,确保是01背包而不是完全背包
最后计算结果时,从O向右枚举,保证了重量不为负数,dp[i]>=0,保证价值不为负数
再从中选max(i-O+dp[i])
代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 #include<iostream> 9 #include<algorithm> 10 #define RG register int 11 #define rep(i,a,b) for(RG i=a;i<=b;++i) 12 #define per(i,a,b) for(RG i=a;i>=b;--i) 13 #define ll long long 14 #define inf (1<<29) 15 #define O 100000 16 #define maxn 105 17 #define maxm 200005 18 using namespace std; 19 int n; 20 int dp[maxm],v[maxn],w[maxn]; 21 inline int read() 22 { 23 int x=0,f=1;char c=getchar(); 24 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 25 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 26 return x*f; 27 } 28 int main() 29 { 30 n=read(); 31 rep(i,1,n) w[i]=read(),v[i]=read(); 32 //memset(dp,-63,sizeof(dp)); 33 dp[O]=0; 34 rep(i,1,n) 35 { 36 if(v[i]>=0) 37 per(j,maxm-1,v[i]) 38 dp[j]=max(dp[j],dp[j-v[i]]+w[i]); 39 else 40 rep(j,0,maxm-1+v[i]) 41 dp[j]=max(dp[j],dp[j-v[i]]+w[i]); 42 } 43 int ans=0; 44 rep(i,O,maxm-1) 45 if(dp[i]>=0) 46 ans=max(ans,dp[i]+i-O); 47 cout<<ans; 48 return 0; 49 }