Dfs+强剪枝。
一个很棒的题解:http://blog.csdn.net/lyy289065406/article/details/6698787/
discuss里有一组很好的数据:
535064
9084
答案为:535956
先从m < n开始搜,再从n > m搜索,并用f数组记录剪枝。
#include <cstdio>
#include <cstring>
char n[105];
int k;
int m[105];
int mod[105][10];
int f[105][10000+5]; //f[pos][rest]记录在pos位置上余数为rest时更改的数字个数cnt.
bool Dfs(int pos, int cnt, int rest) {
if (rest == 0) {
return true;
}
if (pos >= strlen(n) || cnt <= 0 || f[pos][rest] >= cnt) {
return false;
}
//m < n
for (int i = pos; i < strlen(n); i++) {
for (int j = 0; j < n[i] - '0'; j++) {
if (i == 0 && j == 0) {
continue;
}
m[i] = j;
int rest_num = (rest - (mod[strlen(n)-i-1][n[i]-'0'] - mod[strlen(n)-i-1][m[i]]) + k) % k;
if (Dfs(i + 1, cnt - 1, rest_num)) {
return true;
}
}
m[i] = n[i] - '0';
}
//m > n
for (int i = strlen(n) - 1; i >= pos; i--) {
for (int j = n[i] - '0' + 1; j <= 9; j++) {
m[i] = j;
int rest_num = (rest + mod[strlen(n)-i-1][m[i]] - mod[strlen(n)-i-1][n[i]-'0']) % k;
if (Dfs(i + 1, cnt - 1, rest_num)) {
return true;
}
}
m[i] = n[i] - '0';
}
f[pos][rest] = cnt;
return false;
}
int main() {
while (scanf("%s", n) == 1) {
scanf("%d%*c", &k);
memset(m, 0, sizeof(m));
memset(mod, 0, sizeof(mod));
memset(f, 0, sizeof(f));
for (int j = 0; j <= 9; j++) {
mod[0][j] = j % k;
}
for (int i = 1; i <= strlen(n); i++) {
for (int j = 0; j <= 9; j++) {
mod[i][j] = (mod[i-1][j] * 10) % k;
}
}
for (int i = 0; i < strlen(n); i++) {
m[i] = n[i] - '0';
}
int rest = 0;
for (int i = strlen(n) - 1; i >= 0; i--) {
rest = (rest + mod[strlen(n)-i-1][m[i]]) % k;
}
for (int i = 0; i <= strlen(n); i++) {
if (Dfs(0, i, rest)) {
for (int j = 0; j < strlen(n); j++) {
printf("%d", m[j]);
}
putchar('\n');
break;
}
}
}
return 0;
}