poj 3624(背包问题DP)

背包问题是一个经典的动态规划问题。给定n个物品的重量和价值问如何装包能使得在有限的包容量的情况下能装的价值最高。

决策:当得到一个物品时,做一个决策,是否把这个物品放到包中,一种决策是不放这个物品,一种决策是置空包放入该物品并将剩余空间放入剩余空间的最优解。

这样就可以写出状态转移方程:

d(i, j) = max{ d(i - 1, j), d(i - 1, j - w(i) ) + v(i) }

d(i, j) = max{ d(i + 1, j), d( i + 1, j - w(i)) + v(i) }

这两个递推方程的结果相同,第一个是用d(i, j)表示把前i个物品放到重量量为j的背包中的最大总价值,第二个方程的d(i, j)表示把第i, i + 1, …. ,n个物品放到重量为j的背包中的最大总价值。

二维数组dp

由于

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int dp[200][200];
int w[200];
int v[200];       

int main() {
    freopen("input.txt", "r", stdin);
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &w[i], &v[i]);
        }
        for(int i = 1; i <= n; i++) {
            for(int j = 0; j <= m; j++) {
                dp[i][j] = (i == 1 ? 0 : dp[i-1][j]);
                if (j >= w[i]) dp[i][j] = max(dp[i][j], dp[i-1][j-w[i]] + v[i]);
            }
        }
        printf("%d\n", dp[n][m]);
    }
    return 0;
}

由于这道题的数量级很大所以会出现爆内存问题,还好有lql大神,告诉我紫书上有一个滚动数组 的方法。

以下是滚动数组方法:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int dp[13000];
int w, v;

int main() {
    freopen("input.txt", "r", stdin);
    int n, m;
    while(~scanf("%d%d", &n, &m)) {
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++) {
            scanf("%d%d", &w, &v);
            for(int j = m; j >= 0; j--) {
                if (j >= w)  dp[j] = max(dp[j], dp[j-w]+v);
            }
        }
        printf("%d\n", dp[m]);
    }
    return 0;
}

滚动数组方法让我想到了斐波那契数列的迭代写法:

    v[0] = 1;
    v[1] = 2;
    for(int i = 2; i <= n; i++) 
    {
        v[i] = v[0] + v[1];
    }

猜你喜欢

转载自blog.csdn.net/sunmaoxiang/article/details/80905857