POJ 1426 Find The Multiple(DP + 抽象01背包)

题意:

给定一个数 n(n <= 200), 输出一个由 01 组成的十进制数(长度不超过100),并且这个数是 n 的倍数。

思路:

1. 由于题目限定了 n 的范围以及输出的范围,普通的 DFS/BFS 是能够解题的,只不过时间复杂度较高,达到 70ms+;

2. 抓住由“01 组成的十进制数”这个特性,可以把问题抽象成由:1,10,100,1000,10000……其中任意多个组成的符合题意的数;

3. dp[i][j] 表示前 i 个数,能否表示成余 j 的形式,能则记录最小的一个;不能则为 0。dp[i][j] = min(dp[i-1][j], dp[i-1][r] + 10i);

4. 特别注意的是,当 j = 0 时,要特殊处理下,因为即使 dp[i-1][0] = 0, 去求 dp[i][r] 仍然是正确且必要的。最终时间为 0ms;

#include <iostream>
#include <algorithm>
using namespace std;

__int64 dp[110][210];

__int64 solve(int n) {
    int rem = 1;
    __int64 exp = 1;

    memset(dp[0], 0, sizeof(dp[1]));
    dp[0][1] = 1;

    for (int i = 1; i <= 100; i++) {
        exp *= 10;
        rem = (rem * 10) % n;
        for (int j = 0; j < n; j++) {
            dp[i][j] = dp[i-1][j];
        }
        for (int j = 0; j < n; j++) {
            if (dp[i-1][j] || j == 0) {
                int r0 = (j + rem) % n;
                if (dp[i][r0] == 0)
                    dp[i][r0] = exp + dp[i-1][j];
                if (r0 == 0) 
                    return dp[i][r0];
            }
        }
    }
    return 0;
}

int main() {
    int n;
    while (scanf("%d", &n) && n) {
        if (n == 1) 
            printf("1\n");
        else
            printf("%I64d\n", solve(n));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/2969831.html