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;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------