您的位置:首页 > 其它

poj 2184 dp(兼具聪明和幽默的奶牛)

2014-11-04 20:09 267 查看
题意:有n头奶牛,每个奶牛有一个聪明值(s)和幽默值(f)(-1000<=值<=1000)。现欲选出若干奶牛,使得这些奶牛的聪明值之和与幽默值之和再求和所得的数值最大,且需要满足聪明值之和和幽默值之和都非负。

思路:一开始以为和1015陪审团是同样的思路,后来发现不行。于是参考了http://www.cnblogs.com/rainydays/archive/2012/07/04/2576077.html

思路变为d[i][s]=f的形式。表示用前i头牛构成s属性和为s的情况下f属性和最大为多少。状态转移从两种情况来,即用或者不用当前的牛。dp[i][j] = max(dp[i - 1][j - s[i]] + f[i], dp[i - 1][j])。在实际操作的时候可以将第一维去掉,进行空间上的优化。但是由于s[i]的值有正有负,所以在填写数组的顺序要根据s[i]的值来决定,若为正则从右到左(类似01背包的空间优化),若为负则从左到右。

注意:动态规划中状态维和值是可以相互转化的。状态维过多,效率低的时候,可以把将其转化为数组值;同理,数组值不唯一无法规划时,可以增加状态维使状态更详细。

循环边界可以直接从0到2M,见版本1。

我写的两个循环边界是:for(j = M+i*1000-1000;j>=0;j--)和for(j = M-i*1000+1000;j<=M*2;j++)。又参考了http://blog.csdn.net/qinmusiyan/article/details/8028627的思路后缩小了边界范围。见版本2。

版本1:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 100000
int a[105],b[105];
int dp[(N<<1)+5];
int n;
int main(){
int i,j,res=0;
scanf("%d",&n);
for(i = 1;i<=n;i++)
scanf("%d %d",&a[i],&b[i]);
for(i = 0;i<=2*N;i++)
dp[i] = -INF;
dp
= 0;
for(i = 1;i<=n;i++){
if(a[i] >= 0){
for(j = 2*N-a[i];j>=0;j--)
if(dp[j] != -INF)
dp[j+a[i]] = max(dp[j+a[i]],dp[j]+b[i]);
}else{
for(j = -a[i];j<=2*N;j++)
if(dp[j] != -INF)
dp[j+a[i]] = max(dp[j+a[i]],dp[j]+b[i]);
}
}
for(i = N;i<=2*N;i++)
if(dp[i]>=0)
res = max(res,i+dp[i]-N);
printf("%d\n",res);
return 0;
}


版本2:

#include <stdio.h>
#include <string.h>
#define max(a,b) ((a)>(b)?(a):(b))
#define INF 0x3fffffff
#define N 105
#define M 100000
int n,m;
int dp[M*2+5],s
,f
;
int main(){
//freopen("a.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
int i,j,res=0,high,low;
high = low = M;
for(i = 1;i<=n;i++)
scanf("%d %d",&s[i],&f[i]);
for(i = 0;i<=M*2;i++)
dp[i] = -INF;
dp[M] = 0;
for(i = 1;i<=n;i++){
if(s[i] >= 0){
for(j = high;j>=low;j--)
dp[j+s[i]] = max(dp[j+s[i]],dp[j]+f[i]);
high += s[i];
}
else{
for(j = low;j<=high;j++)
dp[j+s[i]] = max(dp[j+s[i]],dp[j]+f[i]);
low += s[i];
}
}
for(i = M;i<=M*2;i++)
if(dp[i]>=0)
res = max(res,i-M+dp[i]);
printf("%d\n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: