UVA-624 CD (01背包+路径记忆)

题意:给一个播音机(背包),然后给你一段播放时间n(容量),每个对应又m 个磁带,每个磁带都有自己的时间(容量),求能播放最长的时间以及输出所选择的磁带(能塞背包的最大体积以及选择的物品),每种磁带只能播放一次;

思路:这便是0/1背包的题(物品只能使用一次),同时与之不同的是要 输出所选择的物品。我们就用二维dp来记录(一维不能记录到底最后选择的是哪个物品)

如果dp[i][j]== dp[i-1][j-v[i]]+v[i],意味着这是恰好符合上次转移过来的路径,倒退最后就可以获得物品(由于是逆序得到物品,所以也要逆序输出)

完整代码:

#include <iostream>
#include <cstdio>
#include <cstring>
const int maxn =1e5;
int dp[30][maxn];
int v[maxn];
int ans[maxn];
using namespace std;
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++){
            scanf("%d",&v[i]);
        }
        for(int i=1;i<=m;i++){
            for(int k= n;k>0;k--){
                dp[i][k] += max(dp[i-1][k-v[i]]+v[i],dp[i-1][k]);
                if(k<v[i]) dp[i][k] = dp[i-1][k];
            }
        }
        int cnt = 0;
        for(int i=m,j=n;i>0;i--){//下标与背包容量 
            if(j-v[i]>=0&&dp[i][j]== dp[i-1][j-v[i]]+v[i]){
                ans[cnt++] = v[i];//从v[i]处推导来
                j -= v[i]; 
            }
        }
        for(int i=cnt-1;i>=0;i--){
            cout<<ans[i]<<" ";
        }
        cout<<"sum:"<<dp[m][n]<<endl;
    
    }
}

                                     

原文地址:https://www.cnblogs.com/Tianwell/p/11223591.html