题目链接:点击打开链接
题目大意:给出一个n和一个k 求m
要求1、m要和n相同的位数
要求2、m要整除k
要求3、如果1和2满足,那么m要和n有尽量少的不同位
要求4、如果1、2、3满足,要使m尽量的小
简单的一个深搜,但是直接被要求吓蒙,,,,,
要求1和2直接可以在搜索时判断,要求3可以在深搜时给出可以改变的位数(有0到len(n)),而要求4需要控制在搜索是要从小的开始搜,即从100000到999999,因为在深搜之前就控制了可以改变的次数,所以在搜索时不用担心要求3,只要使要求1要求2满足就可以,那么搜到的第一个就是最小的。
注意剪枝:
1、在每一次变化后都要直接计算出余数,当余数为0时,返回1,而不是一定要搜到最后一位。
mod[i][j] = (j*10^i)%k
2、flag[i][j]当搜到第i位余数为j时,没有找到结果的(修改位数),当以后遇到修改位数<=flag[i][j]时直接返回0。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define INF 0x3f3f3f3f
char str[110] ;
int k , len , a[110] ;
int mod[110][10] ;
int flag[110][11000] ;
void init() {
int i , j ;
for(j = 0 ; j < 10 ; j++)
mod[0][j] = j%k ;
for(i = 1 ; i < 110 ; i++)
for(j = 0 ; j < 10 ; j++)
mod[i][j] = mod[i-1][j]*10%k ;
}
int dfs(int num,int pos,int s) {
if( s == 0 ) return 1 ;
if( num == 0 || pos == -1 ) return 0 ;
if( num <= flag[pos][s] ) return 0 ;
int i , temp ;
for(i = 0 ; i <= 9 ; i++) {
if( pos == len-1 && i == 0 ) continue ;
if( i < a[pos] ) {
temp = a[pos] - i ;
a[pos] = i ;
if( dfs(num-1,pos-1,(s-mod[pos][temp]+k)%k) ) return 1 ;
a[pos] += temp ;
}
else if( i == a[pos] ) {
if( dfs(num,pos-1,s) ) return 1 ;
}
else {
temp = i-a[pos] ;
a[pos] = i ;
if( dfs(num-1,pos-1,(s+mod[pos][temp])%k) ) return 1 ;
a[pos] -= temp ;
}
}
flag[pos][s] = max(flag[pos][s],num);
return 0 ;
}
int main() {
int i , j , s , temp ;
//freopen("1.txt","r",stdin) ;
//freopen("2.txt","w",stdout) ;
while( scanf("%s %d", str, &k) != EOF ) {
memset(flag,-1,sizeof(flag)) ;
len = strlen(str) ;
for(i = len-1 ; i >= 0 ; i--) {
a[len-1-i] = str[i] - '0' ;
}
init() ;
for(i = s = temp = 0; i < len ; i++) {
s = (mod[i][a[i]]+temp)%k ;
temp = s ;
}
for(i = 0 ; i <= len ; i++) {
if( dfs(i,len-1,s) ) break ;
}
for(i = len-1 ; i >= 0 ; i--)
printf("%d", a[i]) ;
printf("\n") ;
}
return 0 ;
}
/*
535064
9084
535956
19169 15724
15724
3902 153
3978
*/