uva 624 (01背包打印路径)

来源:互联网 发布:有线通 知乎 编辑:程序博客网 时间:2024/06/06 09:42

题意:

给张磁带,可以录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 longusing 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;}


0 0