POJ 2184 Cow Exhibition (01揹包變形 + 技巧 好題)

_TCgogogo_發表於2015-11-16
Cow Exhibition
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10847   Accepted: 4286

Description

"Fat and docile, big and dumb, they look so stupid, they aren't much 
fun..." 
- Cows with Guns by Dana Lyons 

The cows want to prove to the public that they are both smart and fun. In order to do this, Bessie has organized an exhibition that will be put on by the cows. She has given each of the N (1 <= N <= 100) cows a thorough interview and determined two values for each cow: the smartness Si (-1000 <= Si <= 1000) of the cow and the funness Fi (-1000 <= Fi <= 1000) of the cow. 

Bessie must choose which cows she wants to bring to her exhibition. She believes that the total smartness TS of the group is the sum of the Si's and, likewise, the total funness TF of the group is the sum of the Fi's. Bessie wants to maximize the sum of TS and TF, but she also wants both of these values to be non-negative (since she must also show that the cows are well-rounded; a negative TS or TF would ruin this). Help Bessie maximize the sum of TS and TF without letting either of these values become negative. 

Input

* Line 1: A single integer N, the number of cows 

* Lines 2..N+1: Two space-separated integers Si and Fi, respectively the smartness and funness for each cow. 

Output

* Line 1: One integer: the optimal sum of TS and TF such that both TS and TF are non-negative. If no subset of the cows has non-negative TS and non- negative TF, print 0. 

Sample Input

5
-5 7
8 -6
6 -3
2 1
-8 -5

Sample Output

8

Hint

OUTPUT DETAILS: 
Bessie chooses cows 1, 3, and 4, giving values of TS = -5+6+2 = 3 and TF 
= 7-3+1 = 5, so 3+5 = 8. Note that adding cow 2 would improve the value 
of TS+TF to 10, but the new value of TF would be negative, so it is not 
allowed. 

Source



題目大意:每個奶牛有一個s值和一個f值,現在要求選出一些奶牛他們的s值和f值的和最大,且他們的f值的和,s值的和都不能小於0

題目分析:最簡單的想法三維dp,顯然在時間和空間上都是不允許的,第一個技巧是通過普通01揹包的思想先去掉第一維的n,對於正數就是倒敘迴圈,然後把第二維的s做為陣列的下標,第三維的f做為陣列的值,則降為1維,設dp[i]表示s和值為i時s和與f和的和的最大值(是不是很拗口?),因為可能為負,所以直接加一個大數字,本題單個和的最大為100000,則拿100000當做0點,所以陣列要開到200000,根據01揹包,正數倒推,負數正推,原因是要保證是用i-1的狀態來修改i的狀態,然後在j >= 100000且dp[j] >= 0時,取ans的最大值即可,有一個優化,如果s[i]和f[i]都是負數,則不需要加進去判斷,因為加進去顯然不會影響最優解
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const MAX = 105;
int const CON = 200000;
int const INF = 1 << 30;
int dp[CON + 5], s[MAX], f[MAX];

int main()
{
	int n, ans = 0;
	scanf("%d" ,&n);
	for(int i = 0; i < n; i++)
		scanf("%d %d", &s[i], &f[i]);
	for(int i = 0; i <= CON; i++)
		dp[i] = -INF;
	dp[CON / 2] = 0;
	for(int i = 0; i < n; i++)
	{
		if(s[i] > 0 || f[i] > 0)
		{
			if(s[i] > 0)
			{
				for(int j = CON; j >= s[i]; j--)
				{
					if(dp[j - s[i]] > -INF)
					{
						dp[j] = max(dp[j], dp[j - s[i]] + f[i]);
						if(j >= CON / 2 && dp[j] > 0)
							ans = max(ans, dp[j] + j - CON / 2);
					}
				}
			}
			else
			{
				for(int j = s[i]; j <= CON + s[i]; j++)
				{
					if(dp[j - s[i]] > -INF)
					{
						dp[j] = max(dp[j], dp[j - s[i]] + f[i]);
						if(j >= CON / 2 && dp[j] > 0)
							ans = max(ans, dp[j] + j - CON / 2);
					}
				}
			}
		}
	}
	printf("%d\n", ans);
}



相關文章