动态规划 (Dynamic Programming)

文章目录

  • 背包 DP
    • 01 背包
    • 完全背包
    • 多重背包
    • 混合背包

背包 DP

01 背包

1. 洛谷 P2871 [USACO07DEC] Charm Bracelet S

题目链接:洛谷 P2871

01 背包模板题,不过多解释。

#include 
using namespace std;

constexpr int N = 3500, M = 13000;
int n, m, w[N], d[N], dp[M];

int main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> w[i] >> d[i];
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= n; i++)
        for (int j = m; j >= w[i]; j--) dp[j] = max(dp[j], dp[j - w[i]] + d[i]);
    cout << dp[m] << endl;
    return 0;
}

2. P1855 榨取kkksc03

题目链接:洛谷 P1855

跟前面的模板题很像,只是 d p dp dp 数组从一维变成了二维。设 d p j , k dp_{j, k} dpj,k 为考虑到第 i i i 个愿望,需要金钱为 j j j,需要时间为 k k k 最多可以实现的愿望个数,那么 d p j , k = m a x ( d p j , k , d p j − m , k − t + 1 ) dp_{j, k} = max(dp_{j, k}, dp_{j - m, k - t} + 1) dpj,k=max(dpj,k,dpjm,kt+1)

#include 
using namespace std;

#define int long long

int n, M, T, dp[205][205];

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> M >> T;
    for (int i = 1; i <= n; i++) {
        int m, t;
        cin >> m >> t;
        for (int j = M; j >= m; j--)
            for (int k = T; k >= t; k--) dp[j][k] = max(dp[j][k], dp[j - m][k - t] + 1);
    }
    cout << dp[M][T] << endl;
    return 0;
}

完全背包

1. P1616 疯狂的采药

题目链接:洛谷 P1616

完全背包模板题,不过多解释。

#include 
using namespace std;

#define int long long

constexpr int T = 1e7 + 10, M = 1e4 + 10;
int t, m, a[M], b[M], dp[T];

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr);
    cin >> t >> m;
    for (int i = 1; i <= m; i++) cin >> a[i] >> b[i];
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= m; i++)
        for (int j = a[i]; j <= t; j++) dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
    cout << dp[t] << endl;
    return 0;
}

多重背包

1. P1776 宝物筛选

题目链接:洛谷 P1776

多重背包模板题,二进制分组优化

#include 
using namespace std;

#define int long long

const int N = 1e6 + 10;
int n, W, cnt = 0, w[N], v[N], dp[N];

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> n >> W;
    for (int i = 1; i <= n; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        int res = 1;
        while (c >= res) {
            cnt++;
            v[cnt] = res * a, w[cnt] = res * b;
            c -= res;
            res <<= 1;
        }
        if (c) {
            cnt++;
            v[cnt] = a * c, w[cnt] = b * c;
        }
    }
    for (int i = 1; i <= cnt; i++) {
        for (int j = W; j >= w[i]; j--) dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
    }
    cout << dp[W] << endl;
    return 0;
}

混合背包

核心思想:将不同种类的背包分别处理。

1. P1833 樱花

题目链接:洛谷 P1833

混合背包模板题,与前面几种背包不同的是,需要对集中不同类型的背包进行分类处理。

#include 
using namespace std;

#define int long long

int n, T, dp[1005];
string ts, te;

signed main() {
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    cin >> ts >> te >> n;
    int hs = 0, ms = 0, he = 0, me = 0, i;
    for (i = 0; i < ts.size() && ts[i] != ':'; i++) hs = hs * 10 + ts[i] - '0';
    for (i = i + 1; i < ts.size(); i++) ms = ms * 10 + ts[i] - '0';
    for (i = 0; i < te.size() && te[i] != ':'; i++) he = he * 10 + te[i] - '0';
    for (i = i + 1; i < te.size(); i++) me = me * 10 + te[i] - '0';
    T = (he - hs) * 60 + me - ms;
    for (int i = 1; i <= n; i++) {
        int t, c, p;
        cin >> t >> c >> p;
        if (!p)
            for (int j = t; j <= T; j++) dp[j] = max(dp[j], dp[j - t] + c);
        else {
            for (int k = 1; k <= p; k *= 2) {
                int tt = t * k, cc = c * k;
                for (int j = T; j >= tt; j--) dp[j] = max(dp[j], dp[j - tt] + cc);
                p -= k;
            }
            if (p) {
                int tt = t * p, cc = c * p;
                for (int j = T; j >= tt; j--) dp[j] = max(dp[j], dp[j - tt] + cc);
            }
        }
    }
    cout << dp[T] << endl;
    return 0;
}

你可能感兴趣的:(学习笔记,动态规划,算法,c++)