题意: 给你N头奶牛,每头奶牛都有两种属性S和F、,每种属性的属性值可以为负值、问你S的和和F的和的最大值为多少、
思路: 背包转换,可以S的值看做容量F的值看做价值、 依照正常的背包做就可以了、最后只要遍历一遍所有和值找出最大值输出便可、 有一个问题需要注意,那就是有负值的问题 因为有负值,我们可以将他在数组里面的位置移位,移到为整数的位置、 也就是每个S值最小为-1000 最多有100个,也就是说将0~100000看做左边的值、 100000~200000看做正数值、 要注意的是将dp[100000]的值赋值为0,其余位置负值为负数的极小值、因为我要求的值是固定值,在最后我需要将这个i值与我的dp[i[值进行求和、输出、 所以,每个值里面代表的是,恰好将某个容量的背包装满的情况下我才可以将之加入、否则会影响我的求值、 还需要注意的是,如果S[i]的值>0那么我们正常的按照求dp值来求取我需要的数值、 那么如果S[i]<0的话就要将之从小到大来选择、 因为此时我的S[i]值为负数,那么 j- S[i] >j 按照我们正常的dp[的思想从后向前求的话,会影响后面的值,所以要从前向后选取、那么是从0一直到哪个位置呢? 一定是200000+S[i] 因为S[i]<0 所以我最大的值是不可能超过200000+S[i]的、 还有就是要注意的是,S[i] <0&&F[i]<0的情况、 因为S[i]<0的时候,我的存取情况是按照从0一直到200000+S[i] 来选择的、 那么既然F[i]]<0的话、有可能会发生数组越界的情况、 需要加个判断来解决这个问题、 最后追寻有将之便利一遍找出最大的和值将之输出便可、
哦对了,还有一些需要注意的问题,那就是首先S[i]>0的时候,为什么我要将之由200000~S[i] 因为我要求解的是每一个能装载S[i]的不同容量的背包的值,因为我要求出最大值嘛、有可能虽然有的S[i]的值并不是很大,但是F[i] 的值是会影响我最后求值的、 所以我每一种情况都不要放弃,都要求出来、 而当S[i]<0的时候,我的S值的和值最大为200000+S[i] 跟刚才说的一样,每一种情况我都不放弃,因为我要求的是最后的S和F 的和值的最大值,并不是某种值的最大值、
我的代码不知为什么在POJ上面提交的时候用G++过得了,用C++就过不到,我也不知道为什么、 自己的知识量还是不够,还需努力学习~
AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=99999999;
const int maxn=200010;
const int maxm=110;
int N;
int S[maxm],F[maxm];
int dp[maxn];
int main()
{
while(scanf("%d",&N)!=EOF){
for(int i=0;i<=maxn;i++)
dp[i]=-inf;
for(int i=0;i<N;i++)
scanf("%d %d",&S[i],&F[i]);
dp[100000]=0;
for(int i=0;i<N;i++){
if(S[i]<0&&F[i]<0) continue;
if(S[i]>0){
for(int j=maxn;j>=S[i];j--){
dp[j]=max(dp[j],dp[j-S[i]]+F[i]);
}
}
else{
for(int j=0;j<200000+S[i];j++){
dp[j]=max(dp[j],dp[j-S[i]]+F[i]);
}
}
}
int ans=-inf;
for(int i=100000;i<=200000;i++){
if(dp[i]>=0&&(i-100000+dp[i])>ans){
ans=i-100000+dp[i];
}
}
if(ans<0)
printf("0\n");
else
printf("%d\n",ans);
}
return 0;
}