zoukankan      html  css  js  c++  java
  • HDU 4433 locker(12年天津,DP)

    4576 njczy2010 C Accepted 860 KB 140 ms G++ 2063 B 2014-10-16 09:51:19

    哎,为啥1000*100*100的复杂度的dp就不敢敲了呢,,,真是2

    涉及到可能有后效性的时候,一维就不行了,要扩维。本题,一个状态的变化会影响后两个,所以要用三维。

    lockerTime Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1418    Accepted Submission(s): 620

    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
     
    Source
     
    Recommend
    zhoujiaqi2010   |   We have carefully selected several similar problems for you:  5065 5064 5063 5062 5061 
     
     

    题目:给出两个串,每次可以选择连续的1-3个数字,进行同时加1或者同时减1,问最少经过多少次操作,将一个串转变为另外一个串

    http://acm.hdu.edu.cn/showproblem.php?pid=4433 

    以前有类似的题目,BFS就可以了

    不过这题的数据量太大,听说也有不少是搜索过的

    我写了一个矬B的搜索,反正是挂了,没加什么优化

    训练的时候,yobobobo的DP解法比较接近,可是最终貌似卡在后效性上?

    dp[i][j][k]表示 前i个已经完全匹配,而这时候,第i+1个已经加了j位,第i+2位已经加了k

    转移分为两步,枚举加,枚举减

    注意如果第i位加了a,第i+1位加了b,第i+2位加了c,那么a>=b>=c这个关系不能错

    以下题解转自: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]的最小值了。
     
    注意处理的是初始化过程,全部初始化为INF,dp[0][0][0]=0;
    还有转移的时候,i==1和i==2单独处理下。。
    转移最多是1000*100*100。
    是可以接受的。
     
    我一开始做的时候增加了以为dp[i][x][y][z]表示了后面三位,好理解,但是TLE了。
    减少一维表示就AC了。
     
     
    具体看代码吧!
    注释的很清楚了。
      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<cstdio>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<queue>
      8 #include<map>
      9 #include<set>
     10 #include<string>
     11 //#include<pair>
     12 
     13 #define N 1005
     14 #define M 1000005
     15 #define mod 1000000007
     16 #define inf 0x3f3f3f3f
     17 //#define p 10000007
     18 #define mod2 100000000
     19 #define ll long long
     20 #define LL long long
     21 #define maxi(a,b) (a)>(b)? (a) : (b)
     22 #define mini(a,b) (a)<(b)? (a) : (b)
     23 
     24 using namespace std;
     25 
     26 char s1[N];
     27 char s2[N];
     28 int a[N];
     29 int dp[N][12][12];
     30 int n;
     31 
     32 void ini()
     33 {
     34     n=strlen(s1);
     35     memset(dp,inf,sizeof(dp));
     36     int i;
     37     a[0]=0;
     38     for(i=0;i<n;i++){
     39         a[i+1]=s1[i]-s2[i];
     40         if(a[i+1]<0) a[i+1]+=10;
     41     }
     42    // for(i=1;i<=n;i++){
     43    //     printf("%d",a[i]);
     44    // }printf("
    ");
     45     a[n+1]=0;
     46     a[n+2]=0;
     47 }
     48 
     49 
     50 void solve()
     51 {
     52     int i,j,k,jj,kk,t1,t2;
     53     dp[0][0][0]=0;
     54     for(i=1;i<=n;i++){
     55         for(j=0;j<=9;j++){
     56             for(k=0;k<=9;k++){
     57                 t1=(a[i]-j+10)%10;
     58                 for(jj=0;jj<=t1;jj++){
     59                     for(kk=0;kk<=jj;kk++){
     60                         dp[i][ (jj+k)%10 ][kk]=min(dp[i][ (jj+k)%10 ][kk],dp[i-1][j][k]+t1);
     61                     }
     62                 }
     63 
     64                 t2=10-t1;
     65                 for(jj=0;jj<=t2;jj++){
     66                     for(kk=0;kk<=jj;kk++){
     67                         dp[i][ (k-jj+10)%10 ][(10-kk)%10]=min(dp[i][ (k-jj+10)%10 ][(10-kk)%10],dp[i-1][j][k]+t2);
     68                     }
     69                 }
     70             }
     71         }
     72     }
     73 
     74    // for(i=1;i<=n;i++){
     75     //        for(j=0;j<=9;j++){
     76     //            for(k=0;k<=9;k++) printf(" i=%d j=%d k=%d dp=%d
    ",i,j,k,dp[i][j][k]);
     77      //       }
     78     //    }
     79     return ;
     80 }
     81 
     82 void out()
     83 {
     84     printf("%d
    ",dp[n][0][0]);
     85 }
     86 
     87 int main()
     88 {
     89     //freopen("data.in","r",stdin);
     90     //freopen("data.out","w",stdout);
     91     //scanf("%d",&T);
     92    // for(int ccnt=1;ccnt<=T;ccnt++)
     93    // while(T--)
     94     while(scanf("%s%s",s1,s2)!=EOF)
     95     {
     96         //if(n==0 && k==0 ) break;
     97         //printf("Case %d: ",ccnt);
     98         ini();
     99         solve();
    100         out();
    101     }
    102 
    103     return 0;
    104 }
  • 相关阅读:
    树莓派学习笔记(三)——远程调试树莓派程序(Pycharm实现)
    树莓派学习笔记(一)——系统安装与远程显示
    记 laravel 排除CSRF验证
    thinkPHP5 生成微信小程序二维码 保存在本地
    微信小程序 rich-text 富文本中图片自适应
    Laravel 中自定义 手机号和身份证号验证
    laravel Excel 导入
    微信小程序之页面跳转(tabbar跳转及页面内跳转)
    关于MySQL事务和存储引擎常见FAQ
    微信小程序点击保存图片到本地相册——踩坑
  • 原文地址:https://www.cnblogs.com/njczy2010/p/4028114.html
Copyright © 2011-2022 走看看