动态规划——初步

练习题集

Greedy Tino

滚动数组

#include <cstdio>
#include <algorithm>

const int INF = 1e9;

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int t;
    while (scanf("%d", &t) != EOF) {
        int caseid = 0;
        while (t--) {
            int n;
            scanf("%d", &n);
            int w[101] = {0};
            int cnt = 0;
            bool hasZero = false;
            for (int i = 1; i <= n; ++i) {
                scanf("%d", &w[++cnt]);
                if (w[cnt] == 0) {
                    cnt--;
                    hasZero = true;
                }
            }
            n = cnt;
            int dp[2][4001];
            int offset = 2000;
            for (int i = 0; i < 4001; ++i) dp[0][i] = -INF;
            dp[0][offset] = 0;
            int *des = dp[0];
            int *src = dp[1];
            for (int i = 1; i <= n; ++i) {
                std::swap(des, src);
                for (int j = -2000; j <= 2000; ++j) {
                    int temp = -INF;
                    if (j + w[i] <= 2000 && src[j + offset + w[i]] != -INF) 
                        temp = src[j + offset + w[i]] + w[i];
                    if (j - w[i] >= -2000 && src[j + offset - w[i]] != -INF) 
                        temp = std::max(temp, src[j + offset - w[i]] + w[i]);
                    des[j + offset] = std::max(temp, src[j + offset]);
                }
            }
            printf("Case %d: ", ++caseid);
            if (des[offset] == 0) puts(hasZero ? "0" : "-1");
            else printf("%d
", des[offset] / 2);
        }
    }
    return 0;
}
View Code

Watch The Movie

二维背包问题是指每件物品都具有两种不同的开销,选择这件物品必须同时承担这两种开销,在选择物品的时候必须保证两种开销都不会超过相应的背包容量,求选择物品可以得到最大的权重。设第i件物品所需的两种开销分别为v[i]和u[i],两种开销所对应的背包容量分别为V和U,物品的价值为w[i]。

分析:相比经典的01背包问题,二维背包问题增加了一维开销,于是我们需要在状态上增加一维。设s[i][j][k]表示将前i件物品放入两种容量分别为j和k的背包时所能获得的最大权重,则状态转移方程为s[i][j][k]=max{s[i-1][j][k], s[i-1][j-v[i]][k-u[i]]+w[i]},递推边界为当i=0时s[i][j][k]=0。和01背包类似,状态的维数可以很容易地从三维降低到二维,具体实现见代码。

#include <cstdio>
#include <algorithm>

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    int t;
    while (scanf("%d", &t) != EOF) {
        while (t--) {
            int n, m, l;
            int val[101];
            int lon[101];
            int dp[101][1001] = {0};
            scanf("%d%d%d", &n, &m, &l);
            for (int i = 1; i <= n; ++i) 
                scanf("%d%d",&lon[i], &val[i]);
            for (int i = 1; i <= m; ++i) {
                for (int j = 0; j <= l; ++j) 
                        dp[i][j] = -1e9;
            }
            for (int i = 1; i <= n; ++i) { 
                for (int j = l; j >= lon[i]; --j) 
                    for (int k = m; k >= 1; --k) 
                        dp[k][j] = std::max(dp[k][j], dp[k - 1][j - lon[i]] + val[i]);
            }
            if (dp[m][l] > 0) 
                printf("%d
", dp[m][l]);
            else 
                puts("0");
        }
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/fripside/p/3561120.html