「JSOI2010」找零钱的洁癖

「JSOI2010」找零钱的洁癖

传送门
个人感觉很鬼的一道题。。。
首先我们观察到不同的数最多 (50) 个,于是考虑爆搜。
但是这样显然不太对啊,状态数太多了。
然后便出现了玄学操作:
( ext{BFS}) 的过程中,如果队列中的元素太多了(具体多少我也搞不清)就不搜了,相当于卡时。
但这样又可能会WA,然后就贪心一下就好了???
我反正是不知道为什么可以
可以看这篇博客
参考代码:

#include <algorithm>
#include <cstdio>
#include <queue>
#include <map>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
 
const int _ = 1000002;
 
int aim, n, a[_], ans, now;
map < int, bool > M;
queue < pair < int, int > > Q;
 
int main() {
#ifndef ONLINE_JUDGE
    file("cpp");
#endif
    scanf("%d", &aim);
    while (scanf("%d", &a[++n]) != EOF) ; --n;
    ans = 0x3f3f3f3f;
    sort(a + 1, a + n + 1);
    Q.push(make_pair(0, 0)), M[0] = 1;
    while (!Q.empty()) {
        pair < int, int > x = Q.front(); Q.pop();
        if (x.first == aim) { ans = x.second; break ; }
        for (rg int xx, i = 1; i <= n; ++i) {
            if (x.first < aim && !M[xx = x.first + a[i]]) M[xx] = 1, Q.push(make_pair(xx, x.second + 1));
            if (x.first > aim && !M[xx = x.first - a[i]]) M[xx] = 1, Q.push(make_pair(xx, x.second + 1));
        }
        if (Q.size() > 1000000) break ;
    }
    if (ans != 0x3f3f3f3f) { printf("%d
", ans); return 0; }
    ans = 0, now = aim;
    for (rg int i = n; i >= 1; --i) {
        if (a[i] == 0) continue ;
        ans += now / a[i];
        now -= now / a[i] * a[i];
    }
    printf("%d
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zsbzsb/p/12246240.html