这题不太好想啊。。。。我以为是记忆化搜索但是感觉最后的状态不好转移啊。别人都是用三维dp写的,感觉很巧啊。
binshen写的:http://www.cnblogs.com/kuangbin/archive/2012/10/27/2742672.html
这题的意思就相当于是一个数字密码锁。
每次可以正向或者反向旋转连续的1-3个数字。求从现在状态转到目标状态需要的最少步数。
题目给了两个长度一样的由0-9组成的字符串。就相当于每次操作可以选择连续的1-3个数字加1或者减1.这不过这个加和减是循环的。0减1到9,9加1到0.
一看就是DP。
这不过DP方程不好想,也不好表示状态。
dp[i][x][y]表示处理到第i个,后面两个数字是x,y,把前i位转正确需要的最少步数。
计算dp[i][x][y]时,前i-2位是题目给的现在状态的值,第i-1位是x,第i位是y,就是把前i位转正确。
要把dp[i]的状态转移到dp[i-1]去。
把第i位从x转到目标态b[i]去,就可以把状态转移了。
和第i位相关的转动有三种:一是单转第i位,二是转第i位和第i-1位,三是转第i位、第i-1位和第i-2位。
根据三种可以确定 dp[i-1][xx][yy]中的xx,yy;
转动分为正转和反转。
如果第i位是正转,转正确需要d1步。
那么第i-1和第i-2位正转的不是是小于等于d1的。而且i-2的步数小于等于i-1。
如果第i位是正转,转正确需要d2步。
那么第i-1和第i-2位正转的不是是小于等于d2的。而且i-2的步数小于等于i-1。
这样DP的时候i从1到n转移过去。
处理dp[i]的时候,dp[1~(n-1)][0~9][0~9]都是已知的。就很容易确定dp[i][0~9][0~9]的最小值了。
locker
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1494 Accepted Submission(s): 662
Problem Description
A password locker with N digits, each digit can be rotated to 0-9 circularly.
You can rotate 1-3 consecutive digits up or down in one step.
For examples:
567890 -> 567901 (by rotating the last 3 digits up)
000000 -> 000900 (by rotating the 4th digit down)
Given the current state and the secret password, what is the minimum amount of steps you have to rotate the locker in order to get from current state to the secret password?
Input
Multiple (less than 50) cases, process to EOF.
For each case, two strings with equal length (≤ 1000) consists of only digits are given, representing the current state and the secret password, respectively.
Output
For each case, output one integer, the minimum amount of steps from the current state to the secret password.
Sample Input
111111 222222 896521 183995
Sample Output
2 12
#include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <iomanip> #include <stdio.h> #include <string> #include <queue> #include <cmath> #include <time.h> #include <stack> #include <map> #include <set> #define eps 1e-8 ///#define LL long long #define LL __int64 #define INF 0x3f3f3f #define PI 3.1415926535898 #define mod 1000000007 using namespace std; const int maxn = 1010; int dp[maxn][10][10]; char str1[maxn], str2[maxn]; int num1[maxn]; int num2[maxn]; int main() { while(~scanf("%s %s",str1, str2)) { int n = strlen(str1); for(int i = 0; i < n; i++) { num1[i+1] = str1[i]-'0'; num2[i+1] = str2[i]-'0'; } for(int i = 0; i <= n; i++) for(int j = 0; j < 10; j++) for(int k = 0; k < 10; k++) dp[i][j][k] = INF; dp[0][0][0] = 0; for(int i = 1; i <= n; i++) { for(int x = 0; x < 10; x++) { if(i <= 1 && x > 0) break; for(int y = 0; y < 10; y++) { int dx = (num2[i]-y+10)%10; int dy = (y-num2[i]+10)%10; int xx, yy; if(i == 1) { xx = yy = 0; dp[i][x][y] = min(dp[i][x][y], dp[i-1][xx][yy]+min(dx, dy)); continue; } if(i == 2) { xx = 0; for(int j = x; j <= x+dx; j++) { yy = j%10; dp[i][x][y] = min(dp[i][x][y], dp[i-1][xx][yy]+dx); } for(int j = x; j >= x-dy; j--) { yy = (j+10)%10; dp[i][x][y] = min(dp[i][x][y], dp[i-1][xx][yy]+dy); } continue; } for(int j = 0; j <= dx; j++) { for(int k = j; k <= dx; k++) { xx = (num1[i-2]+j)%10; yy = (x+k)%10; dp[i][x][y] = min(dp[i][x][y], dp[i-1][xx][yy]+dx); } } for(int j = 0; j <= dy; j++) { for(int k = j; k <= dy; k++) { xx = (num1[i-2]-j+10)%10; yy = (x-k+10)%10; dp[i][x][y] = min(dp[i][x][y], dp[i-1][xx][yy]+dy); } } } } } int x = 0; int y = 0; if(n >= 2) x = num1[n-1]; if(n >= 1) y = num1[n]; cout<<dp[n][x][y]<<endl; } return 0; }