题意:
给张磁带,可以录c分钟的歌,然后给n首时间为vi的歌,问这张磁带最长可以录多少分钟的歌,并打印。
解析:
磁带长度为背包容量,每首歌为每个物品,歌的长度为物品重量,每首歌价值也为物品重量。
状态转移方程:
dp[ i ] [ j ] = max(dp[ i - 1 ] [ j ], dp[ i - 1 ] [ j - v[i] ] + v[i])
dp[i][j]表示在磁带长度为j时放入第i首歌的最长时间。
对于第i首歌,若不取,则dp[ i - 1 ] [ j ];若取,dp[ i - 1 ] [ j - v[i] ] + v[i]。
打印时直接递归。
path[i][j]记录的是当前磁带的长度总和,打印时,若path[i - 1][j]小于path[i][j],表明插入了v[i],打印。
void print(int i, int j) { if (i == 0) return; print(i - 1, path[i][j]); if (path[i][j] < j) printf("%d ", v[i]); }
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> #include <stack> #include <vector> #include <queue> #include <map> #define LL long long using namespace std; const int maxn = 20 + 10; const int inf = 0x3f3f3f3f; const double eps = 1e-8; const double pi = 4 * atan(1.0); const double ee = exp(1.0); int c, n; int v[maxn]; int dp[maxn][10000]; int path[maxn][10000]; void print(int i, int j) { if (i == 0) return; print(i - 1, path[i][j]); if (path[i][j] < j) printf("%d ", v[i]); } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); #endif // LOCAL while (scanf("%d", &c) == 1) { memset(v, 0, sizeof(v)); memset(dp, 0, sizeof(dp)); scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &v[i]); } for (int i = 1; i <= n; i++) { for (int j = 0; j <= c; j++) { dp[i][j] = (i == 1 ? 0 : dp[i - 1][j]); path[i][j] = j; if (v[i] <= j) { if (dp[i][j] < dp[i - 1][j - v[i]] + v[i]) { dp[i][j] = dp[i - 1][j - v[i]] + v[i]; path[i][j] = j - v[i]; } } } } print(n, c); printf("sum:%d\n", dp[n][c]); } return 0; }