• UVa1631


    题意:

    有一个n(n≤1000)位密码锁,每位都是0~9,可以循环旋转。每次让1~3个相邻数字同时往上或者往下转一格,567890->567901(最后3位向上)。输入初始状态和终止状态(长度不超过1000),问最少要转几次。

    这道题刚开始看有点蒙,不知道应该如何转密码锁上面的格,然后通过经验能够感觉出来最优的转动方案是可以按照

    从左到右的顺序来移动到正确的位置的,这样我们将无序的转动变成了有序的转动,自然问题就简化了许多,

    然后通过观察题意(每次让1~3个相邻数字同时往上或者往下转一格),我发现1-3个相邻的数字说明了如果按照从左到右的

    顺序进行转动后那么可以仅仅影响前面或后面1-3个格子的,然后发现影响后面的格子会更好写程序,所以下面是状态与转移方程:
      d(i,j,k,p)表示前i-1个已经配对,其中i、i+1、i+2分别对应j、k、p还需要最少波动次数
      状态转移方程:其中第i个一定要拨动使之配对,其余的i+1、i+2可以随着i的拨动进行改变(也可以不改变),可以往上下拨。
      最后答案为d(0,a[0],a[1],a[2])

    这需要使用记忆化搜索求解,刚开始我拨动的时候犯了一个错误,如果i拨动x次,那么i+1、i+2也一定拨动x次,或者仅仅i+1拨动x次,

    这样其实是错误的(想一想,为什么),后面拨动的次数是任意的(但需要保证小于前面拨动次数),下面是代码:

    // UVa 1631 
    /*
      d(i,j,k,p)表示前i-1个已经配对,其中i、i+1、i+2分别对应j、k、p还需要最少波动次数
      状态转移方程:其中第i个一定要拨动使之配对,其余的i+1、i+2可以随着i的拨动进行改变(也可以不改变),可以往上下拨。
      最后答案为d(0,a[0],a[1],a[2])
    */
    #include <cstdio> 
    #include <cstring> 
    #include <algorithm>
    using namespace std; 
    
    const int maxn = 1000 + 10; 
    const int INF = 1000000003; 
    
    char s[maxn], s2[maxn];
    int len, a[maxn], b[maxn]; 
    int d[maxn][11][11][11]; 
    
    int dp(int cur, int x, int y, int z) { 
      if (cur >= len) return 0; 
      
      int& ans = d[cur][x][y][z]; 
      if (ans >= 0) return ans; 
      
      ans = INF;
      int down = (b[cur]+10-x)%10, up = (x+10-b[cur])%10;
      for (int i = 0; i <= down; ++i) 
        for (int j = 0; j <= i; ++j) 
          ans = min(ans, dp(cur+1,(y+i)%10,(z+j)%10,a[cur+3])+down);
      for (int i = 0; i <= up; ++i) 
        for (int j = 0; j <= i; ++j) 
          ans = min(ans, dp(cur+1,(y+10-i)%10,(z+10-j)%10,a[cur+3])+up);
      return ans; 
    }
    
    int main() { 
      while (scanf("%s%s", s, s2) == 2) {
          len = strlen(s); 
          for (int i = 0; i < len; ++i) a[i] = s[i] - '0'; 
          for (int i = 0; i < len; ++i) b[i] = s2[i] - '0';
          a[len] = a[len+1] = a[len+2] = b[len] = b[len+1] = b[len+2] = 0;   
          memset(d, -1, sizeof(d)); 
          printf("%d
    ", dp(0,a[0],a[1],a[2]));
      }
      return 0;
    }
  • 相关阅读:
    异地主从双机热备份实战
    基于Crawler4j的WEB爬虫
    【转】TCP拥塞控制
    js定时器setTimeout和setInterval的使用
    制作 macOS Sierra U盘USB启动安装盘方法教程 (亲测)
    VMware 14 安装 macOS10.13 详细图文教程
    解决多线程下@Autowired无法注入
    MySQL 使用自增ID主键和UUID 作为主键的优劣比较详细过程(从百万到千万表记录测试)
    关于MYSQL
    关于Mybaits
  • 原文地址:https://www.cnblogs.com/yifeiWa/p/11330489.html
Copyright © 2020-2023  润新知