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

浙公网安备 33010602011771号