台州 OJ 5072 Cow Exhibition 01背包

给出 n 头牛,每头牛有两个属性 smartness 和 funness ,求从所有的牛里选一些牛,使这些牛的 smartness + funness 的和最大,且 smartness 的和、funness的和都要大于零。

定义 dp[i][j] 表示前 i 头牛在 smartness 为 j 时 funness 的最大值。

dp[i][j+s[i]] = max(dp[i-1][j+s[i]], dp[i-1][j] + f[i])    s[i]、f[i] 分别表示第 i 头牛的 smartness 和 funness。

因为 smartness 可能为负,要保证在 dp 时下标要大于等于零,所以在 dp 的过程中将 j 加一个数,最后求答案时再转化回原来的数。

 

代码(用了两个一维数组滚动优化):

#include <iostream>
#include <cstring>
using namespace std;

const int MAX = 2005;
const int INF = 0x3f3f3f3f;
const int zero = 100000; 

int n;
int now[MAX*100], pre[MAX*100];
int s[MAX], f[MAX];

int main(){
    freopen("input.txt", "r", stdin);
    int ans = 0, minS = 0, maxS = 0;
    cin >> n;
    for(int i=1; i<=n; i++){
        cin >> s[i] >> f[i];
        if(s[i] >= 0 && f[i] >= 0){        //smartness 和 funness 都大于 0 的牛一定选 
            ans += s[i] + f[i];
            i--; n--;
        }else if(s[i] < 0 && f[i] < 0){        //都小于 0 的一定不选 
            i--; n--;
        }
    }
    
    //初始化 
    memset(now, -INF, sizeof(now));
    now[zero] = 0;
    memcpy(pre, now, sizeof(now));
    
    //DP
    minS = maxS = zero;        // 0 变成 100000,将 smartness 为负数的情况转化为全部是正数 
    for(int i=1; i<=n; i++){
        for(int j=minS; j<=maxS; j++){
            now[j+s[i]] = max(pre[j+s[i]], pre[j] + f[i]);    //smartness j+s[i] 时,funness 的最大值,考虑第 i 头牛放不放 
        }
        minS = min(minS + s[i], minS);
        maxS = max(maxS + s[i], maxS);
        memcpy(pre, now, sizeof(now));
    }
    
    int maxn = 0;
    for(int i=zero; i<=maxS; i++){
        if(now[i] >= 0){
            maxn = max(maxn, (i-zero) + now[i]);    //要 - zero 转化为原来的 smartness 
        }
    }
    
    cout << ans + maxn;
    
    return 0;
}

 

posted @ 2017-07-27 14:54  淡蓝色光  阅读(94)  评论(0编辑  收藏  举报