poj3373--Changing Digits(DFS+剪枝///记忆化)
题目链接:点击打开链接
题目大意:给出一个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。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 char str[110]; 8 int k,len,a[110]; 9 int mod[110][10]; 10 int flag[110][11000]; 11 void init(){ 12 for(int j=0;j<10;j++) 13 mod[0][j]=j%k; 14 for(int i=1;i<110;i++) 15 for(int j=0;j<10;j++) 16 mod[i][j]=mod[i-1][j]*10%k; 17 } 18 19 int dfs(int num,int pos,int s){ 20 if(s == 0) return 1; 21 if(num == 0 || pos == -1) return 0; 22 if(num <= flag[pos][s]) return 0; 23 int temp ; 24 for(int i=0;i<=9;i++){ 25 if(pos == len-1 && i == 0 ) continue; 26 if(i<a[pos]){ 27 temp=a[pos]-i; 28 a[pos]=i; 29 if(dfs(num-1,pos-1,(s-mod[pos][temp]+k)%k)) return 1; 30 a[pos]+=temp; 31 } 32 else if(i == a[pos]){ 33 if(dfs(num,pos-1,s)) return 1; 34 } 35 else{ 36 temp=i-a[pos]; 37 a[pos]=i; 38 if(dfs(num-1,pos-1,(s+mod[pos][temp])%k)) return 1; 39 a[pos]-=temp; 40 } 41 } 42 flag[pos][s]=max(flag[pos][s],num); 43 return 0; 44 } 45 46 int main(){ 47 int i,j,s,temp; 48 while(scanf("%s %d",str,&k)!=EOF){ 49 memset(flag,-1,sizeof(flag)); 50 len=strlen(str); 51 for(i=len-1;i>=0;i--){ 52 a[len-1-i]=str[i]-'0' ; 53 } 54 init(); 55 for(i=s=temp=0;i<len;i++){ 56 s=(mod[i][a[i]]+temp)%k ; 57 temp=s; 58 } 59 for(i=0;i<=len;i++){ 60 if(dfs(i,len-1,s)) break; 61 } 62 for(i=len-1;i>=0;i--) 63 printf("%d",a[i]); 64 printf("\n"); 65 } 66 return 0; 67 } 68 69 /* 70 535064 71 9084 72 535956 73 74 75 19169 15724 76 15724 77 78 3902 153 79 3978 80 */