P2297 刷图

来源:互联网 发布:java jdbc链接oracle 编辑:程序博客网 时间:2024/06/06 02:37

一句话

01背包,数组负数部分平移到正的部分。

正解

设状态dp[i][j]表示已经处理了i件物品了,且∑ai不大于j的最大的∑(ai+bi)
正如一般的背包问题,转移不难想到是dp[i][j] = max(dp[i-1][j], dp[i-1][j-a]+b)
但是,由于∑ai的值有可能为负数,但是C语言中数组下标为负数时会有出毛病的风险,所以可以将j这一维开成二倍大小(p*2),前p个位置放的是原来负数的部分,后p个位置放原来是正的部分,这样就可以正常进行转移了。

代码

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;const int N = 100 + 10;const int V = 300000;const int inf = 1e8;const int p = 100005;int a, b, l, r, dp[N][V], n, ans;int main() {    freopen("2297.in", "r", stdin);    scanf("%d", &n);    for(int i = 0; i <= n; ++i) {        for(int j = 0; j < V; ++j) {            dp[i][j] = -inf+1;        }    }    dp[0][p] = 0;    for(int i = 1; i <= n; ++i) {        scanf("%d%d", &a, &b);        if(a < 0) l += a;        else r += a;        for(int j = l; j <= r; ++j) {            dp[i][j+p] = max(dp[i-1][j+p], dp[i-1][j+p-a]+b);            if(j >= 0 && dp[i][j+p] >= 0) {                ans = max(ans, dp[i][j+p]+j);            }        }    }    printf("%d\n", ans);    return 0;}
原创粉丝点击