P1159岳麓山上打水

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
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6217755.html