链接
https://vjudge.net/problem/UVA-624
题意
n n n个数字,每个数字使用一次,求不超过 m m m的最大和为多少,并把组成这个最大和的数字输出出来;
分析
这是一个01背包,背包容积为 m m m,物品为数字,体积和价值均为数字大小;这里需要记录路径,方法很多,如果相邻两个阶段之间发生了转移(选取了该物品,就说明使用了该物品,从最后一个阶段向前找);
代码
#include <functional>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>
#define INF 0x7f7f7f7f
#define MAXN 100005
#define N 200005
#define P 2
#define MOD 99991
typedef long long ll;
namespace fastIO {
//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 22)], *p1 = buf, *p2 = buf;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
}
using namespace fastIO;
using namespace std;
int n, m, dp[30][10004], a[10005];
int main() {
while (cin >> m >> n) {
for (int i = 1; i <= n; i++)
cin >> a[i];
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++)
for (int j = m; j >= 0; j--) {
if (j >= a[i])dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - a[i]] + a[i]);
else dp[i][j] = dp[i - 1][j];
}
int k = m;
vector<int>vec;
for (int i = n; i > 0; i--)
if (k >= a[i] && dp[i][k] == dp[i - 1][k - a[i]] + a[i]) {
k -= a[i];
vec.push_back(a[i]);
}
for (int i = vec.size() - 1; i >= 0; i--)
cout << vec[i] << " ";
cout << "sum:" << dp[n][m] << endl;
}
}