记录路径的DP,看的别人的思路。自己写的也不好,时间居然2000+,中间的取余可以打个表,优化一下。
写的各种错,导致wa很多次,写了一下午,自己构造数据,终于发现了最后一个bug。
dp[i][j]表示前i位取余得到j,需要最少改变多少位。
这样可以得到最少改变多少位了,但是,还要保证,最小。学习别人的题解,开一个标记数组,先从后倒回来,把这些可以达到最小的路径都记录下来。
然后再从头找最小的那一条路径。这样就能保证,最小了。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 #define INF 100000000 6 int dp[101][10001]; 7 bool o[101][10001]; 8 int que[101]; 9 int main() 10 { 11 int i,j,k,n,m,t,z,pos; 12 char str[101]; 13 while(scanf("%s%d",str,&m)!=EOF) 14 { 15 n = strlen(str); 16 if(n == 1) 17 { 18 if((str[0]-'0')%m == 0) 19 printf("%d ",str[0]-'0'); 20 else 21 printf("0 "); 22 continue; 23 } 24 for(i = 0; i < n; i ++) 25 { 26 for(j = 0; j < m; j ++) 27 { 28 dp[i][j] = INF; 29 o[i][j] = 0; 30 } 31 } 32 for(i = 1; i < 10; i ++) 33 { 34 t = i%m; 35 if(i == str[0]-'0') 36 z = 0; 37 else 38 z = 1; 39 dp[0][t] = min(dp[0][t],z); 40 } 41 for(i = 0; i < n-1; i ++) 42 { 43 for(j = 0; j < m; j ++) 44 { 45 if(dp[i][j] == INF) continue; 46 for(k = 0; k < 10; k ++) 47 { 48 if(k == str[i+1]-'0') 49 z = 0; 50 else 51 z = 1; 52 dp[i+1][(j*10+k)%m] = min(dp[i+1][(j*10+k)%m],dp[i][j]+z); 53 } 54 } 55 } 56 o[n-1][0] = 1; 57 for(i = n-2; i >= 0; i --) 58 { 59 for(j = 0; j < m; j ++) 60 { 61 if(dp[i][j] == INF) continue; 62 for(k = 0; k < 10; k ++) 63 { 64 if(k == str[i+1]-'0') 65 z = 0; 66 else 67 z = 1; 68 if(dp[i+1][(j*10+k)%m] == dp[i][j]+z&&o[i+1][(j*10+k)%m]) 69 { 70 o[i][j] = 1; 71 } 72 } 73 } 74 } 75 for(i = 1; i < 10; i ++) 76 { 77 t = i%m; 78 if(i == str[0]-'0') 79 z = 0; 80 else 81 z = 1; 82 if(o[0][t]&&dp[0][t] == z) 83 { 84 printf("%d",i); 85 pos = t; 86 break; 87 } 88 } 89 for(i = 1;i < n;i ++) 90 { 91 for(j = 0;j < 10;j ++) 92 { 93 if(j == str[i]-'0') 94 z = 0; 95 else 96 z = 1; 97 if(o[i][(pos*10+j)%m]&&dp[i][(pos*10+j)%m] == dp[i-1][pos]+z) 98 { 99 printf("%d",j); 100 pos = (pos*10+j)%m; 101 break; 102 } 103 } 104 } 105 printf(" "); 106 } 107 return 0; 108 }