1. 程式人生 > 實用技巧 >1068 Find More Coins (30分) 01揹包+路徑

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;
}