【1068 30 01背包】 Find More Coins

传送门

题意

给定\(n\)个数,求出能否从中选出若干数使得和为\(m\),按照类似字典序输出最小的序列

数据范围

\(n\leq 10^{5}\)
\(m\leq 100\)

题解

  • 可以使用dfs深搜,\(m\)范围小,在\(m\)范围内进行搜索,从小到大加入即可
  • \(01\)背包,\(dp[j]\)表示是否有组合方案使得和为\(j\)成立,\(st[i][j]\)表示和为\(j\)时第\(i\)个元素是否被选中
    • 优化掉第一维后,背包容量从大到小
    • 状态转移:\(dp[j] = dp[j] || dp[j - v[i]]\)
    • \(dp[j-v[i]]\)成立,\(st[i][j]=1\)

Code

#include <bits/stdc++.h>
using namespace std;
int main() {
    int n, m; cin >> n >> m;
    vector<int> v(n + 1);
    vector<bitset<105>> st(n + 1);
    bitset<105>dp;
    for (int i = 1; i <= n; ++i) cin >> v[i];
    sort(v.begin() + 1, v.end(), greater<int>());
    dp[0] = st[0][0] = 1;
    for (int i = 1; i <= n; ++i) 
        for (int j = m; j >= v[i]; j--) {
            dp[j] = dp[j] || dp[j - v[i]];
            if (dp[j - v[i]]) st[i][j] = true;
        }
    if (!dp[m]) cout << "No Solution";
    else {
        bool f=0;
        for (int i = n; i >= 1; --i)
            if (st[i][m]) {
                cout << (f ? " " : "") << v[i];
                m -= v[i];
                f=1;
            }
    }
    return 0;
}
posted @ 2021-03-02 16:14  Hyx'  阅读(31)  评论(0)    收藏  举报