1068 Find More Coins (30分) 01背包+路径

题目

https://pintia.cn/problem-sets/994805342720868352/problems/994805402305150976

题意

N个硬币,选出一些,刚好凑成M元
按01背包求解,背包容量M,若能装满,说明有解
若有多解,输出序列最小的(难点)

Sample Input 1:

8 9
5 9 8 7 2 3 4 1

Sample Output 1:

1 3 5 (2 3 4、9...)

Sample Input 2:

4 8
7 2 4 3

Sample Output 2:

No Solution

思路

对01背包算法改进下,序列降序排序
标记f[][]
参考:https://www.liuchuo.net/archives/2323

code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int N,M;
int w[10006];
int dp[10006][101];//前i个硬币选出价值为j的
int f[10006][101];
bool cmp(int x,int y) {return x>y;}
int main()
{
    cin>>N>>M;
    for(int i=1;i<=N;++i) cin>>w[i];
    sort(w+1,w+1+N,cmp);
    for(int i=1;i<=N;++i)
    {
        for(int j=M;j>=0;--j)
        {
            if(j>=w[i]) {
                if(dp[i-1][j]<=dp[i-1][j-w[i]]+w[i]) {
                    dp[i][j]=dp[i-1][j-w[i]]+w[i];
                    f[i][j]=1;
                }
                else dp[i][j]=dp[i-1][j];
            }
            else dp[i][j]=dp[i-1][j];
        }
    }
    vector<int>ans;
    if(dp[N][M]==M) {
        int i=N,j=M;
        while(j>0)
        {
            if(f[i][j]) {
                ans.push_back(w[i]);
                j-=w[i];
            }
            i--;
        }
        for(int i=0;i<ans.size();++i) {
            cout<<ans[i];
            if(i!=ans.size()-1) cout<<" ";
        }
    }
    else cout<<"No Solution";
    return 0;
}
原文地址:https://www.cnblogs.com/liuyongliu/p/13565192.html