UVA - 1631 Locker 记忆化搜索

问题

旋转密码锁,一次至多可以旋转相邻的三个数字,最大一千位数字,可以上旋或者下旋,问从现在的数字最少需要旋转多少次才能得到想要的数字

分析

状态dp[k][a][b][c],k代表从左到右第k位数字,第0-k-1位都已经被调整好,现在调整第k,k+1,k+2位数字,a,b,c分别等于第k,k+1,k+2位数字的大小,状态dp[k][a][b][c]表示从现在的状态到把剩下的数字完全调整好需要至少多少次旋转
状态转移:
a==n2[k],这一位不用旋转, d p [ k ] [ a ] [ b ] [ c ] = d p [ k + 1 ] [ b ] [ c ] [ n 1 [ k + 3 ] ] dp[k][a][b][c]=dp[k+1][b][c][n1[k+3]]
a!=n2[k],可以上旋或者下旋,旋转格数为t,同时可以选择第k+1,k+2位也跟着旋转,第k+1位旋转的个数一定不大于第k位旋转的格数,第k+2旋转的个数一定不大于第k+1旋转的个数
调整第k位时,第k位旋转t格,第k+1旋转i格,第k+2旋转j格,由旋转方式造成的限制:j<=i<=t
因为 t是旋转第k位的总次数(第k位旋转一位,旋转两位,旋转三位次数之和)
i是旋转第k+1位的次数(第k位旋转两位,旋转三位次数之和)
j是旋转第k+2位的次数(第k位旋转三位次数之和)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int maxn=1005,Inf=0x3f3f3f3f;
string s1,s2;
int dp[maxn][11][11][11],n1[maxn],n2[maxn],len1;

inline int rotate(int x){
    if(x>=10) return x-=10;
    return x;
}

//k之前的都被调整好了,a,b,c分别代表 第k,k+1,k+2位数字 的现在状态,dp[k][a][b][c]是从当前到全部复原的最小旋转次数
int DFS(int k,int a,int b,int c){
    if(k==len1) return 0;
    int &ans=dp[k][a][b][c];
    if(ans<Inf) return ans;

    int t=0,t2=n2[k]; 
    if(t2==a) return ans=min(ans,DFS(k+1,rotate(b),rotate(c),n1[k+3]));  //相等时,不用调整这一位

    //向上旋转
    if(t2>a)  t=t2-a;  //调整第k位时,第k位旋转t格,第k+1旋转i格,第k+2旋转j格,由旋转方式造成的限制:j<=i<=t
    else t=10+t2-a;
    for(int i=0;i<=t;++i){
        for(int j=0;j<=i;++j){
            ans=min(ans,DFS(k+1,rotate(b+i),rotate(c+j),n1[k+3])+t);
        }
    }
    //向下旋转
    if(t2<a) t=a-t2;
    else t=10+a-t2;
    for(int i=0;i<=t;++i){
        for(int j=0;j<=i;++j){
            ans=min(ans,DFS(k+1,rotate(10+b-i),rotate(10+c-j),n1[k+3])+t);
        }
    }
    return ans;
}

int main(void){
    while(cin>>s1>>s2){
        len1=s1.length();
        for(int i=0;i<len1;++i){
            n1[i]=s1[i]-'0';
            n2[i]=s2[i]-'0';
        }
        s1[len1]=s2[len1]=0;
        s1[len1+1]=s2[len1+1]=0;
        for(int i=0;i<=len1;++i){
            for(int j=0;j<10;++j){
                for(int k=0;k<10;++k){
                    for(int l=0;l<10;++l) dp[i][j][k][l]=Inf;
                }
            }
        }
        printf("%d\n",DFS(0,n1[0],n1[1],n1[2]));
    }
}

发布了50 篇原创文章 · 获赞 0 · 访问量 709

猜你喜欢

转载自blog.csdn.net/zpf1998/article/details/104081671