题意:
给你一串密码,每次我们可以转动1-3个数字,求转出最终答案的最小步数
思路:
感觉自己好坑,最开始想的是dp[cur][t1][t2][t3]也就是t1的位置以及连续的三个数的状态
但是卡死循环了,于是乎改成dp[cur][t1][t2](当前的位置以及它后面的数的状态)
每次求出当前位置转到正确答案时要的步数,然后枚举3种情况(也就是后面两个数是否一起转动)
但是中途发现思路有问题,111 --> 322 这种它会给出答案三,然而应该是2
(感觉最近课真的多,还要考试- -,都没时间做题)
通过上面那个例子发现,当前位置并不是一次旋转到正确答案是最优解(感觉思考问题是太片面了)
可能自己选转几格,再带动后面两个转动,322 -> 222 -> 111
所以对于后两个的可能枚举0 --> t(t为转动到正确答案的步数)
而且t2转动的步数≥a[cur+2]步数,因为第三个位置转动的前提便是t2转动
所以得出个循环,然后记忆化搜索
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <vector> #include <algorithm> #include <functional> using namespace std; const int maxn = 1005; const int INF = 0x3f3f3f3f; char str1[maxn]; char str2[maxn]; int a[maxn]; int b[maxn]; int dp[maxn][10][10]; int len; int up(int s,int t) //上旋 { if(s >= t) return s-t; else return (s-t+10)%10; } int down(int s,int t) //下旋 { if(t >= s) return t-s; else return (t-s+10)%10; } int DFS(int cur,int t1,int t2) { if(cur >= len) return 0; if(dp[cur][t1][t2] != -1) return dp[cur][t1][t2]; int t = up(b[cur],t1); int ans = INF; for(int i = 0; i <=t; i++) //枚举后个数的情况 for(int j = i; j <= t; j++) { ans = min(ans,DFS(cur+1,(t2+j)%10,(a[cur+2]+i)%10) + t); } t = down(b[cur],t1); for(int i = 0; i <=t; i++) for(int j = i; j <= t; j++) { ans = min(ans,DFS(cur+1,(t2-j+10)%10,(a[cur+2]-i+10)%10) +t); } return dp[cur][t1][t2] = ans; } int main() { while(scanf("%s%s",str1,str2) != EOF) { len= strlen(str1); for(int i = 0; i < len; i++) { a[i] = str1[i] - '0'; b[i] = str2[i] - '0'; } a[len] = a[len+1] = b[len] = b[len+1] = 0; memset(dp,-1,sizeof(dp)); printf("%d ",DFS(0,a[0],a[1])); } return 0; }