UVA

来源:互联网 发布:诱导源码 编辑:程序博客网 时间:2024/06/08 07:45

题意:给定两个密码串,每次可以让1~3个相邻的密码向上或者向下滚动,每个密码是09 ,问最少需要多少次滚动可以让原串成为目标串?


思路:假设当前要让第i位密码还原,我们可以同时转动[i,i+1,i+2],[i,i+1],[i],不同的转动方式会影响后序的转动,那么可以枚举(i,i+1,i+2)三个密码的转动情况来进行记忆化搜索。
dp(i,a,b,c)表示当前已经还原了前i1个密码,且第i个密码的值是a,第i+1个密码的值是b,第i+2个密码的值是c的情况下需要的最小转动次数。

AC代码

#include <cstdio>#include <cmath>#include <cctype>#include <bitset>#include <algorithm>#include <cstring>#include <utility>#include <string>#include <iostream>#include <map>#include <set>#include <vector>#include <queue>#include <stack>using namespace std;#pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10#define inf 0x3f3f3f3f#define PI pair<int, int> typedef long long LL;const int maxn = 1000 + 5;int dp[maxn][10][10][10];char st[maxn], ed[maxn];int s[maxn], g[maxn], n;int dfs(int cur, int a, int b, int c) {    if(cur >= n) return 0;    int& ans = dp[cur][a][b][c];    if(ans != -1) return ans;    ans = inf;    int step;     //向上旋转    if(a <= g[cur]) step = g[cur]-a;    else step = g[cur]+10-a;    for(int i = 0; i <= step; ++i)        for(int j = 0; j <= i; ++j) {            ans = min(ans, dfs(cur+1, (b+i)%10, (c+j)%10, s[cur+3]) + step);        }    //向下旋转    if(a <= g[cur]) step = a+10-g[cur];    else step = a-g[cur];    for(int i = 0; i <= step; ++i)        for(int j = 0; j <= i; ++j) {            ans = min(ans, dfs(cur+1, (b-i+10)%10, (c-j+10)%10, s[cur+3]) + step);        }    return ans;}int main() {    while(scanf("%s %s", st, ed) == 2) {        memset(dp, -1, sizeof(dp));        n = strlen(st);        for(int i = 0; i < n; ++i) {            s[i] = st[i]-'0';            g[i] = ed[i]-'0';        }        s[n] = s[n+1] = g[n] = g[n+1] = '0';        printf("%d\n", dfs(0, s[0], s[1], s[2]));    }    return 0;}

如有不当之处欢迎指出!