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