【POJ 2184】【Cow Exhibition】

题目:

"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. 

解题思路:

一群牛分别拥有智慧值,和幽默值,问咱们这些给定的牛中,智商值和幽默值的和最大,看到这道题,瞬间惊呆了,这是什么玩意,求二者的最大和,并且要求不能小于0,后来参考题解发现,以智慧值做为dp[]数组的下标,然后里边存放幽默值,dp[i]表示的是,当智慧值为i的时候,幽默值能达到最大值,就酱。当你以为这样就欧克的时候,你会发现,智商值,幽默值居然有负的,什么鬼,负的,脑洞太大了,这个时候简单的利用dp数组就没办法实现了,因为下标是不能为负的,所以,可以坐标转移一下,已知每头牛的智商值上限为1000,最多有100头牛,所以可以将坐标原点转移到100000处,将负的坐标转移到正的地方处理,然后,很注意的一点就是,当智商值为正的时候,是正常的01背包,没什么可说的, 但是当智商值为负的时候,你会发现,你如果还是按照正常的01模板去求解的话,是错误的,因为正常的01背包的实现是根据上一状态为基础实现的,由上一状态推出当前状态的最优解,当为正的时候,dp[j]取决于dp[j-s[i]]比它的值小的dp值,智商值为负的话,就颠倒过来了,应该由当前区间内比它大的值推出。之后就没坑点啥的了。

参考了一个很不错的代码,思路清晰,https://blog.csdn.net/keysona/article/details/45751903

ac代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1e9
using namespace std;
int dp[200002],s[101],f[101];

int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&s[i],&f[i]);//输入数据,智慧,风趣值 
	for(int i=0;i<=100000+1000*n;i++)
	{//数据范围的处理,就是-1000*100——1000*100区间内 
		dp[i]=-inf;
	}//将dp数组初始化为-inf 无限小 
	//dp的 i 是存放的前i头牛的智商值总和 
	//dp[i] 就是当智商和为i是 幽默感的最大值
	//最后求解的是 i+dp[i]的最大值,即智商值加幽默值 
	dp[100000]=0;
	for(int i=1;i<=n;i++)
	{
		if(s[i]<=0&&f[i]<=0)
			continue;//如果都是负的,选择跳过 
		if(s[i]<0)
		{//负的话,就是正序求解,因为要递推,由上一已知状态推出下一状态 
			for(int j=0;j<=100000+1000*n+s[i];j++)
				dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
		}
		else
		{//正的话,直接01背包求解 
			for(int j=100000+1000*n;j>=s[i];j--)
				dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
		}
	}
	int ans=-inf;
	for(int i=100000;i<=100000+1000*n;i++)
	{
		if(dp[i]>=0)
			ans=max(ans,dp[i]+i-100000);
	}//遍历寻找最大值 
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42505741/article/details/81746465