http://poj.org/problem?id=2184
题意:
第一行为N,代表下面有N组数据,下面每一行有S和F分别代表一头牛的智商和幽默度(有正有负),现在要你算出
要选哪些牛,是求当智商大于0时,幽默度最大的时候的智商与幽默度的总和,总和如果为负的话输出0,正的话直接输
出总和的值。
坑爹:
因为这相当于01背包的问题了,智商为背包中的体积,幽默度为背包中的价值,但是智商可能为负,访问数组下标
的时候会错误。
初始化要将 数组 f 赋值为 -0x3fffffff(其实-200000就够了) 并把f[1000000] = 0 因为幽默度能可能出现
负数。
解法:
要解决数组下标可能会访问到负的时候的问题,我将整个数组下标+100000 然后在后面计算总和的时候减去100000
就行了,智商的范围为什么是-100000到100000? 因为有100组数据,如果每个都是1000的话就是100000了。
进行01背包的时候害要分cost是正是负,当正的时候 j - 200000 → cost , 当负的时候 j - cost → 200000 ,
因为0到100000的时候智商是为负的,100000到200000的时候智商是为正的。
View Code
1 #include<iostream> 2 using namespace std; 3 4 const int maxn = 200000 + 1001; 5 const int INF = -1 * 0x3fffffff; 6 int N; 7 8 struct Cow 9 { 10 int TS; 11 int TF; 12 }; 13 14 struct Cow cow[maxn]; 15 int f[maxn]; 16 17 int max(int a,int b) 18 { 19 return a > b ? a : b; 20 } 21 22 void init() 23 { 24 int i; 25 for(i=0; i<maxn; i++) 26 { 27 f[i] = INF; 28 } 29 f[100000] = 0; 30 } 31 32 void ZeroOnePack(int cost,int weight) //逆向 33 { 34 int j; 35 for(j=200000; j>=cost; j--) 36 { 37 if(f[j-cost] > INF) 38 { 39 f[j] = max(f[j] , f[j-cost] + weight); 40 } 41 } 42 } 43 44 void ZeroOnePack1(int cost,int weight) //正向 45 { 46 int j; 47 for(j=cost; j<=200000+cost; j++) 48 { 49 if(f[j-cost] > INF) 50 { 51 f[j] = max(f[j] , f[j-cost] + weight); 52 } 53 } 54 } 55 56 int main() 57 { 58 while(cin>>N) 59 { 60 int i; 61 memset(f,0,sizeof(f)); 62 init(); 63 64 for(i=1; i<=N; i++) 65 { 66 cin>>cow[i].TS>>cow[i].TF; 67 } 68 69 for(i=1; i<=N; i++) 70 { 71 if(cow[i].TS < 0 && cow[i].TF < 0) 72 { 73 continue; 74 } 75 if(cow[i].TS > 0) 76 { 77 ZeroOnePack(cow[i].TS,cow[i].TF); 78 } 79 if(cow[i].TS <= 0) 80 { 81 ZeroOnePack1(cow[i].TS,cow[i].TF); 82 } 83 } 84 85 int MAX = INF; 86 for(i=100000; i<=200000; i++) 87 { 88 if(f[i] >= 0) 89 { 90 MAX = max(MAX , f[i] + i - 100000); 91 } 92 } 93 if(MAX < 0) 94 { 95 cout<<0<<endl; 96 } 97 else 98 { 99 cout<<MAX<<endl; 100 } 101 } 102 return 0; 103 }