Description
有一些奶牛,他们有一定的s值和f值,这些值有正有负,最后让保证s的和为非负且f的和为非负的情况下,s+f的最大值
Input
第一行为奶牛数量n,之后n行每行两个整数表示对应奶牛的s和f值
Output
输出保证s和非负f和非负时的s+f的最大值
Sample Input
5
-5 7
8 -6
6 -3
2 1
-8 -5
Sample Output
8
Solution
将s+100000看作重量,f看作价值,问题转化为01背包问题,最后取dp[i]+i-100000(100000 <=i<=200000,dp[i]>=0)的最大值即可,注意由于01背包省略第一维后为避免后效性,内层循环都是逆着推的,因此s值为负时内层循环方向与s值为正时相反
Code
#include<stdio.h>
#define maxn 100000
#define INF 1<<30
#define max(x,y) ((x)>(y)?(x):(y))
int dp[2*maxn+10],n,s[101],f[101];
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
scanf("%d%d",&s[i],&f[i]);
for(int i=0;i<=2*maxn;i++)//初始化
dp[i]=-INF;
dp[maxn]=0;
for(int i=1;i<=n;i++)//01背包
{
if(s[i]<0&&f[i]<0)//剪枝
continue;
if(s[i]>=0)
{
for(int j=2*maxn;j>=s[i];j--)
if(dp[j-s[i]]>-INF)
dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
}
else
{
for(int j=s[i];j<=2*maxn+s[i];j++)//注意循环方向
if(dp[j-s[i]]>-INF)
dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
}
}
int ans=-INF;
for(int i=maxn;i<=2*maxn;i++)//满足s和非负
if(dp[i]>=0)//满足f和非负
ans=max(ans,dp[i]+i-maxn);//更新s+f最大值
printf("%d\n",ans);
}
return 0;
}