背包dp(模版)

1.01背包问题

题目链接

#include <cstdio>
#include <algorithm>

using namespace std;

const int M = 1010;
int dp[M];

int main() {
    int N, V, v, w;
    scanf("%d%d", &N, &V);
    for (int i = 1; i <= N; ++i) {
        scanf("%d%d", &v, &w);
        for (int j = V; j - v >= 0; --j) {
            dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
    printf("%d", dp[V]);
    return 0;
}

2.完全背包问题

题目链接

#include <cstdio>
#include <algorithm>

using namespace std;
const int M = 1010;
int dp[M];

int main() {
    int N, V, v, w;
    scanf("%d%d", &N, &V);
    for (int i = 1; i <= N; ++i) {
        scanf("%d%d", &v, &w);
        for (int j = v; j <= V; ++j) {
            dp[j] = max(dp[j], dp[j - v] + w);
        }
    }
    printf("%d", dp[V]);
    return 0;
}

3.多重背包问题 I

题目链接

#include <cstdio>
#include <algorithm>

using namespace std;
const int M = 110;
int dp[M];

int main() {
    int N, V, v, w, s;
    scanf("%d%d", &N, &V);
    for (int i = 1; i <= N; ++i) {
        scanf("%d%d%d", &v, &w, &s);
        for (int j = V; j >= 0; --j) {
            for (int k = 1; k <= s; ++k) {
                if (j - k * v >= 0) {
                    dp[j] = max(dp[j], dp[j - k * v] + k * w);
                }
            }
        }
    }
    printf("%d", dp[V]);
    return 0;
}

4.多重背包问题 II

题目链接

#include <cstdio>
#include <algorithm>

using namespace std;
const int M = 2020;
int dp[M];
int v[M], s[M], w[M], vv[M * 10], ss[M * 10], ww[M * 10];

int main() {
    int N, V, cnt = 0;
    scanf("%d%d", &N, &V);
    for (int i = 1; i <= N; ++i) {
        scanf("%d%d%d", &v[i], &w[i], &s[i]);
        for (int j = 1; j <= s[i]; j = j << 1) {
            vv[cnt] = v[i] * j;
            ww[cnt++] = w[i] * j;
            s[i] -= j;
        }
        if (s[i]) {
            vv[cnt] = v[i] * s[i];
            ww[cnt++] = w[i] * s[i];
        }
    }

    for (int i = 0; i < cnt; ++i) {
        for (int j = V; j - vv[i] >= 0; --j) {
            dp[j] = max(dp[j], dp[j - vv[i]] + ww[i]);
        }
    }
    printf("%d", dp[V]);
    return 0;
}
/*
 * 二进制优化
 * s[i] = 1 * 2 * 4 *... * w[i] + temp;
*/

5.多重背包问题 III

题目链接

一般来说二进制就够了,有兴趣可以看一下单调队列优化

多重背包单调队列优化解释链接

#include <iostream>
#include <cstring>
using namespace std;
const int M = 20020;
int dp[M], dp1[M], que[M];
int main()
{
	int N, V;
	cin >> N >> V;
	int w, v, s;
	for (int i = 0; i < N; ++i) {
		cin >> w >> v >> s;
		memcpy(dp1, dp, sizeof(dp));
		for (int j = 0; j < w; ++j) {
			int head = 0, tail = -1;
			for (int k = 0; j + k * w <= V; ++k) {
				if (head <= tail && k - que[head] > s) head++;
				while (head <= tail && dp1[j + k * w] - k * v >= dp1[j + que[tail] * w] - que[tail] * v)
					tail--;
				que[++tail] = k;
				dp[j + k * w] = dp1[j + que[head] * w] + (k - que[head]) * v;

			}
		}
	}
	cout << dp[V] << endl;
	return 0;
}

6.混合背包问题

题目链接

#include <iostream>
#include <cstring>
using namespace std;
int dp[1010], w[1010], v[1010], s[1010], dp1[1010], que[1010];
int main()
{
	int N, V;
	cin >> N >> V;
	for (int i = 0; i < N; ++i) {
		cin >> w[i] >> v[i] >> s[i];
		if (s[i] == -1)
			s[i] = 1;
		if (s[i] == 0) {
			s[i] = V / w[i];
		}
	}
	for (int i = 0; i < N; ++i) {
		memcpy(dp1, dp, sizeof(dp));
		for (int j = 0; j < w[i]; ++j) {
			int head = 0, tail = -1;
			for (int k = 0; j + k * w[i] <= V; ++k) {
				if (head <= tail && k - que[head] > s[i]) head++;
				while (head <= tail && dp1[j + k * w[i]] - k * v[i] >= dp1[j + que[tail] * w[i]] - que[tail] * v[i]) tail--;
				que[++tail] = k;
				dp[j + k * w[i]] = dp1[j + que[head] * w[i]] + (k - que[head]) * v[i];
			}
		}
	}
	cout << dp[V];
	return 0;
}

7.二维费用的背包问题

题目链接

#include <cstdio>
#include <algorithm>

using namespace std;

const int M = 1010;
int dp[M][M];

int main() {
    int N, V, M, v, m, w;
    scanf("%d%d%d", &N, &V, &M);
    for (int i = 1; i <= N; ++i) {
        scanf("%d%d%d", &v, &m, &w);
        for (int j = V; j - v >= 0; --j) {
            for (int k = M; k - m >= 0; --k) {
                dp[j][k] = max(dp[j][k], dp[j - v][k - m] + w);
            }
        }
    }
    printf("%d", dp[V][M]);
    return 0;
}

Adventurer’s Guild(应用题题目链接)

#include <cstdio>
#include <algorithm>

using namespace std;
#define ll long long
ll dp[330][330];

int main() {
    int n, H, S;
    scanf("%d%d%d", &n, &H, &S);
    int h, s, w;
    for (int i = 0; i < n; ++i) {
        scanf("%d%d%d", &h, &s, &w);
        for (int j = H; j - h > 0; --j) {
            for (int k = S; k - s >= 0 || (j - h - abs(k - s) > 0); --k) {
                if (k - s < 0) {
                    int js = abs(k - s);
                    dp[j][k] = max(dp[j][k], dp[j - h - js][k - s + js] + w);
                } else dp[j][k] = max(dp[j][k], dp[j - h][k - s] + w);
            }
        }
    }
    printf("%lld", dp[H][S]);
    return 0;
}

8.分组背包问题

题目链接

#include <cstdio>
#include <algorithm>

using namespace std;

const int M = 110;

int dp[M];
int v[M], w[M];

int main() {
    int N, V;
    scanf("%d%d", &N, &V);
    for (int i = 1; i <= N; ++i) {
        int s;
        scanf("%d", &s);
        for (int j = 1; j <= s; ++j) {
            scanf("%d%d", &v[j], &w[j]);
        }
        for (int j = V; j >= 0; --j) {
            for (int k = 1; k <= s; ++k) {
                if (j - v[k] >= 0)
                    dp[j] = max(dp[j], dp[j - v[k]] + w[k]);
            }
        }
    }
    printf("%d", dp[V]);
    return 0;
}

9.有依赖的背包问题

题目链接

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 110;
int N, V;
int next1[M], head[M], v1[M];
int v[M], w[M];
int dp[M][M]; // dp[i][j]: 选取i时背包容量为j时的最大价值
int cnt = 1, root;

void add(int start1, int end1) {
    v1[cnt] = end1;
    next1[cnt] = head[start1];
    head[start1] = cnt++;
}

void dfs(int now) {
    for (int i = head[now]; i; i = next1[i]) {
        int son = v1[i];
        dfs(son);
        for (int j = V - v[now]; j >= 0; --j) {
            for (int k = 0; k  <= j; ++k) {
                dp[now][j] = max(dp[now][j], dp[now][j - k] + dp[son][k]);
            }
        }
    }
    for (int i = V; i >= v[now]; --i) {
        dp[now][i] = dp[now][i - v[now]] + w[now];
    }
    for (int i = 0; i < v[now]; ++i) dp[now][i] = 0;
}

int main() {
    scanf("%d%d", &N, &V);
    int p;
    for (int i = 1; i <= N; ++i) {
        scanf("%d%d%d", &v[i], &w[i], &p);
        if (p == -1) root = i;
        else
            add(p, i);
    }
    dfs(root);
    printf("%d",dp[root][V]);
    return 0;
}

10.背包问题求方案数

题目链接

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

const int MOD = 1e9 + 7;
const int M = 1010;
int dp[M], g[M];

int main() {
    int N, V, v, w;
    scanf("%d%d", &N, &V);
    for (int i = 0; i <= V; ++i) g[i] = 1; //不装入物品也是一种方案
    for (int i = 0; i < N; ++i) {
        scanf("%d%d", &v, &w);
        for (int j = V; j >= v; --j) {
            /* 多装入一件新物品,采用g[j - v]方案数 */
            if(dp[j - v] + w > dp[j]) {
                dp[j] = dp[j - v] + w;
                g[j] = g[j - v];
            } else if(dp[j - v] + w == dp[j]) { /* 可以采用装入新物品(g[j - v])或者不装入新物品(g[v]),采用g[j - v] + g[v] */
                g[j] = (g[j] + g[j - v]) % MOD;
            }
        }
    }
    printf("%d\n", g[V]);
    return 0;
}

11.背包问题求具体方案

题目链接

#include <iostream>
#include <cstdio>
using namespace std;
const int M = 1010;
int v[M], w[M];
int dp[M][M]; //dp[i][j]表示从第i个物品到最后一个物品,装入容量为j时的背包的最优解
int main() {
    int n, V;
    scanf("%d%d", &n, &V);
    for (int i = 1; i <= n; ++i)scanf("%d%d", &v[i], &w[i]);
    for (int i = n; i >= 0; --i) {
        for (int j = v[i] - 1; j >= 0; --j) {
            dp[i][j] = dp[i + 1][j];
        }
        for (int j = V; j - v[i] >= 0; --j) {
            dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - v[i]] + w[i]);
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (v[i] > V) continue;
        if (dp[i][V] == dp[i + 1][V - v[i]] + w[i]) {
            printf("%d ", i);
            V -= v[i];
        }
    }
    /*
     如果dp[i][j] = dp[i + 1][j]:不选第i个物品时得到最优解
     如果dp[i][j] = dp[i + 1][j - v[i]] +w[i]:必须选第i个物品才可以得到最优解
     如果dp[i][j] = dp[i + 1][j] = dp[i + 1][j - v[i]] + w[i]:选不选第i个物品都可以得到最优解,但是为了字典序最小,也必须选择该物品
     */
    return 0;
}

posted on 2022-06-27 08:29  wxz0v0  阅读(9)  评论(0)    收藏  举报

导航