题目链接:点击打开链接
题目大意:给出一个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 */