poj1426 Find The Multiple

这题直接 \(bfs\) 居然能过是我没想到的。

/**
* poj1426 Find The Multiple
*
*/

#include <cstdio>
#include <queue>
using namespace std;

typedef long long LL;

LL bfs(int n)
{
    queue<LL> Q;
    Q.push(1);
    while (!Q.empty()) {
        LL t = Q.front(); Q.pop();
        if (t % n == 0) return t;
        Q.push(t*10);
        Q.push(t*10+1);
    }
    return 0;
}
int main()
{
    int n;
    while (scanf("%d", &n) && n) {
        printf("%lld\n", bfs(n));
    }
    return 0;
}

这是因为 \(n \le 200\) 时,最小答案恰好在 \(long\ long\) 范围内, 如果数据范围稍微大点,例如 \(n = 396\) 时,这个答案就不对了。

因此,更严谨的 \(AC\) 代码应该是这样的:

/**
* poj1426 Find The Multiple
* 还没有找到合适的剪枝方法
*/

#include <cstdio>
#include <queue>
#include <cstdlib>
#include <cstring>
using namespace std;

typedef long long LL;

const int M = 105, N = 400;
char out[M];  // 存储待输出的倍数
bool book[N];  // 记录mod是否被搜过
int pos;


// 返回true代表已找到答案
bool dfs(int mod, int n)
{
    mod %= n;
    // if (book[mod]) return false;
    if (pos > 100) return false;  // 题目说了不超过100位
    if (mod == 0) return true;

    // book[mod] = 1;
    out[pos++] = '0';
    if (dfs(mod*10, n)) return true;
    --pos;
    out[pos++] = '1';
    if (dfs(mod*10+1, n)) return true;
    --pos;
    return false;
}
int main()
{
    int n;
    while (scanf("%d", &n) && n) {
        memset(book, 0, sizeof book);
        pos = 0;
        out[pos++] = '1';
        if (dfs(1, n)) out[pos] = 0, puts(out);
        else puts("-1");
    }

    return 0;
}

虽然解空间看似有 \(2^{100}\) 种情况,但我们真正要搜索的次数不足 \(2^{22}\) ,别问数字怎么来的,实践出真知。

目前不知道该怎么从数学角度证明最小答案的长度远小于 \(100\) 字符。

posted @ 2021-01-22 16:51  Zewbie  阅读(44)  评论(0)    收藏  举报