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;

}

你可能感兴趣的:(find)