POJ - 2184 Cow Exhibition

题目大意:

每只牛有智慧数值和滑稽值,你的目标是,从n之中挑选x只(可以是0)使得智慧之和和滑稽值和(两个都不能为
0)的总和最大

分析:

01背包(带负权)。很显然我们能选择智慧值做背包容量,来当01背包来做(也可以把滑稽值当背包容量),但
是我们要注意到不管是智慧值还是滑稽值都可能使负的,所以我们要分成两种情况。
1.s[i]>=0,就使普通的01背包,从后往前dp 
2.s[i]<0,从前往后进行dp。
第二种从前往后的原因:因为智慧值为负值,所以当前这个背包容量的价值是由j-s[i](例:s[i]=-1,j=3,则
dp[3]=max(dp[3],dp[3-(-1)]+f[i]))转移过来的,所以使从前往后dp。

code:

#define debug
#include<stdio.h>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<string>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<functional>
#include<iomanip>
#include<map>
#include<set>
#define pb push_back
#define dbg(x) cout<<#x<<" = "<<(x)<<endl;
#define lson l,m,rt<<1
#define cmm(x) cout<<"("<<(x)<<")";
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
const int maxn=1e5;
const int INF=0x3f3f3f3f;
const ll inf=0x7fffff;
const int mod=1e9+7;
const int MOD=10007;
//----
//define
int dp[maxn];
int s[maxn],f[maxn];
//solve
void solve() {
	int n,tots=0;
	cin>>n;
	for(int i=0; i<n; i++) {
		cin>>s[i]>>f[i];
		if(s[i]>=0)tots+=s[i];//偏移量(除负数外的最大背包容量)
	}
	memset(dp,-INF,sizeof(dp));
	dp[tots]=0;//因为背包容量不能为负值,所以加上偏移量,从tots开始(相当于原来01背包中的dp[0]=0) 
	for(int i=0; i<n; i++) {
		if(s[i]>=0)
			for(int j=2*tots; j>=s[i]; j--)dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
		else for(int j=0; j<=2*tots+s[i]; j++)dp[j]=max(dp[j],dp[j-s[i]]+f[i]);
	}
	int ans=0;
	for(int i=tots; i<=2*tots; i++)
		if(dp[i]>0)ans=max(dp[i]+i-tots,ans);
	cout<<ans<<endl;
}

int main() {
	ios_base::sync_with_stdio(0);
#ifdef debug
	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
#endif
	cin.tie(0);
	cout.tie(0);
	solve();
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/visualVK/p/9162974.html