HDU 4433 locker (线性dp)

59 篇文章 0 订阅

OJ题目:click here~~

题目分析:密码锁,给初始状态和目标状态。每次可正向或者反向旋转连续的 1 , 2 , 3 位。数字在0 --- 9 之间循环,即9+1 -> 0, 0-1 -> 9。问从初始状态到目标状态的最少旋转次数。

dp[ i ][ j ][ k ]表示前i位已经匹配了 , 第i + 1目前的数字是 j , 第 i + 2 目前的数字是k , 到目标状态需要的最少旋转次数。显然dp[ n ][ j ] [ k ] 中的最小值为要求的值,其中j 在[ 0 , 9] ,k在 [ 0 , 9];

初值为dp[ 0 ][ a[ 1] ][ a[ 2 ] ] = 0 , 因为要求最小值 , 其他置为inf 。

接下来暴力dp[ i ][ j ][ k ] , 可得到dp[ n ][ j ][ k ] 。

AC_CODE

const int inf = 1<<30;
int dp[1002][11][11];
int a[1002] , b[1002] ,steps[10][10];

int main()
{
    string s1 , s2;
    int i , j , k , m , l , n;
    for(i = 0;i < 10;i++){
        j = 1;
        while((i + j)%10 != i){
            steps[i][(i + j)%10] = j;
            j++;
        }
    }
    while(cin >> s1 >> s2){
        n = s1.length();
        for(i = 0;i < n;i++){//将字符串转化为数字
            a[i+1] = s1[i] - '0';
            b[i+1] = s2[i] - '0';
        }
        for(i = 0;i <= n;i++)
            for(j = 0;j <= 9;j++)
            for(k = 0;k <= 9;k++)
            dp[i][j][k] = inf;
        dp[0][a[1]][a[2]] = 0;//初值
        for(i = 0;i < n;i++)//枚举每一位
            for(j = 0;j < 10;j++)//i+1位为j
            for(k = 0;k < 10;k++){//i+2位为k
                if(dp[i][j][k] < inf){//如果此状态可达,则可得出下一个状态。若不可达,当然不处理。
                    int t = steps[j][b[i+1]];//第i+1位现在为j ,要旋转到b[i + 1]需要t步
                    for(l = 0;l <= t;l++)//第i+2位正向旋转l步
                    for(m = 0;m <= l;m++){//第i+3位正向旋转m步,显然不能超过l
                        dp[i+1][(k+l)%10][(a[i+3] + m)%10] = min(dp[i+1][(k+l)%10][(a[i+3] + m)%10] , dp[i][j][k] + t);
                    }
                    for(l = 0;l <= 10-t;l++)//第i+2位逆向旋转l步
                    for(m = 0;m <= l;m++){//第i+3位逆向旋转m步,显然不能超过l
                        dp[i+1][(k-l+10)%10][(a[i+3]-m+10)%10] = min(dp[i+1][(k-l+10)%10][(a[i+3]-m+10)%10] , dp[i][j][k] + 10 - t);
                    }
                }
            }
        int ans = inf;
        for(i = 0;i < 10;i++)
            for(j = 0;j < 10;j++)
             ans = min(ans , dp[n][i][j]);
        cout << ans << endl;
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值