P1159岳麓山上打水
原创
©著作权归作者所有:来自51CTO博客作者wx634d08b5232a4的原创作品,请联系作者获取转载授权,否则将追究法律责任
P1159岳麓山上打水
https://vijos.org/p/1159
dfsID,第一次听说这东西,但是感觉不太靠谱啊。
一开始的时候,想到了排个序后,然后进行dp,如果要输出字典序最小其实还是可以搞定的,就是2、3、比26小的话,还是可以的。
排序后,只要在转移的时候,如果这个背包有解了的话,就不转移就行了。
但是这题坑爹在需要个数最小,这就不是字典序了。
那么暴力枚举选了多少个桶,那么有2^n种选法。每一种都dp一次。
但是据说,据说在很少步之内就能算出解,然后210ms过了。
26
2
2 26
27
3
2 7 27
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = 20000 + 20;
bool dp[maxn];
int a[maxn];
int sel[maxn];
int tot, n;
int ans[maxn];
bool dfsID(int cur, int has, int up) {
if (has == up) {
for (int i = 0; i <= tot; ++i) dp[i] = false;
dp[0] = true;
for (int i = 1; i <= has; ++i) {
for (int j = ans[i]; j <= tot; ++j) {
dp[j] = dp[j] || dp[j - ans[i]];
}
}
if (dp[tot]) {
cout << has << " ";
for (int i = 1; i <= has; ++i) {
cout << ans[i] << " ";
}
cout << endl;
}
return dp[tot];
}
if (cur > n) return false;
if (n - cur + 1 + has < up) return false;
ans[has + 1] = a[cur];
return dfsID(cur + 1, has + 1, up) || dfsID(cur + 1, has, up);
}
void work() {
cin >> tot >> n;
assert(tot > 0);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
assert(a[i] > 0);
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; ++i) {
if (dfsID(1, 0, i)) {
return;
}
}
}
int main() {
#ifdef local
freopen("data.txt", "r", stdin);
// freopen("data.txt", "w", stdout);
#endif
IOS;
work();
return 0;
}
View Code