zoukankan      html  css  js  c++  java
  • [BZOJ] 1019 [SHOI2008]汉诺塔

    题目链接:[SHOI2008]汉诺塔

    题意:

    给定玩汉诺塔的策略:

    1.上一次移动过的盘不能再次被移动。

    2.三个柱子,给定每两个柱子之间移动的优先级,每次必须执行优先级最高的可行操作。

    题解:

    其实移动方法是被固定的,然后可以发现一些性质。

    根据汉诺塔的一般解题思路,我们肯定是要首先移动第一根柱子最上面的$n-1$个盘到另一个柱子上去。

    那么我们就要思考,在这个过程中,最底下的盘会动吗?

    答案是不会,考虑起始、中间和末尾的移动过程。

    起始的时候肯定是移动最上面那个盘,到优先级最高的地方去。

    中间的时候,要么三个柱子是满的,要么最底下的盘上面还有盘压着,否则的话肯定有一个柱子被空出来了,而如果此时最底下的盘没东西压着,肯定已经移动结束了。

    末尾的时候,最后一步肯定是把最小的盘从一个柱子移动到目标柱子的顶部,于是它不能动,此时,能移动的只有原本柱子上最大的盘,且只能移动到唯一一个空的柱子上去。

    那么就有解题思路了。

    显然当我们要处理某一堆盘的时候,比这一堆大的盘都是被锁死的,动不了,我们可以记搜这个方案。

    $f[i][x]$表示把第$i$个柱子上$x$个盘子移动到另一个柱子需要多少步。

    $g[i][x]$表示把第$i$个柱子上$x$个盘子移动到的是哪一个柱子。

    假如$x=1$,我们就要按照优先级来,移动一步。

    否则的话,我们先移动上面一堆盘,再移动最下面那个盘到空柱子上去。

    接下来我们要移动上面一堆盘,但是此时就会有问题,因为有优先级在,所以上面一堆盘不一定会移动到最大的那个盘的顶部,所以我们需要循环移动,直到两个东西重合。

    显然这个循环次数不会很多,因为如果循环很多都移动不上去的话,看起来就像是一个死循环,但是题目保证有解,所以放心地循环就可以了。

     1 #include <bits/stdc++.h>
     2 #define int long long
     3 #define pii pair<int, int>
     4 #define Mid ((l + r) / 2)
     5 #define lson (rt << 1)
     6 #define rson (rt << 1 | 1)
     7 using namespace std;
     8 int read() {
     9     char c; int num, f = 1;
    10     while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
    11     while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
    12     return f * num;
    13 }
    14 int n, f[4][39], g[4][39];
    15 pii a[10];
    16 void dfs(int x, int cnt) {
    17     if(f[x][cnt] != -1) return ;
    18     f[x][cnt] = 0;
    19     if(cnt == 1) {
    20         f[x][cnt] = 1;
    21         for(int i = 1; i <= 6; i++) {
    22             if(a[i].first == x) {
    23                 g[x][cnt] = a[i].second;
    24                 break;
    25             }
    26         }
    27         return ;
    28     }
    29     dfs(x, cnt - 1);
    30     int nowup = g[x][cnt - 1], nowdown = x;
    31     f[x][cnt] += f[x][cnt - 1];
    32     do{
    33         nowdown = 6 - nowdown - nowup;
    34         f[x][cnt] += 1;
    35         dfs(nowup, cnt - 1);
    36         f[x][cnt] += f[nowup][cnt - 1];
    37         nowup = g[nowup][cnt - 1];
    38     } while(nowup != nowdown);
    39     g[x][cnt] = nowdown;
    40     return ;
    41 }
    42 signed main()
    43 {
    44     n = read();
    45     memset(f, -1, sizeof(f));
    46     for(int i = 1; i <= 6; i++) {
    47         char c[10];
    48         scanf("%s", c + 1);
    49         a[i].first = c[1] - 'A' + 1;
    50         a[i].second = c[2] - 'A' + 1;
    51     }
    52     dfs(1, n);
    53     printf("%lld
    ", f[1][n]);
    54     return 0;
    55 }
    View Code
  • 相关阅读:
    【转载】超级实用且不花哨的js代码大全 -----高级应用(一)
    【 Date 对象 参考手册】
    js随机数random()方法
    【转载】js数组的操作
    【转载】js数组和json的区别
    干货----004----MySQL忘记root密码怎么办?
    PHP框架——TP_0001----ThinkPHP常用配置
    干货----003----乱码解决方法
    Python之路【第二十六篇】:xml模块
    Python之路【番外篇1】:使用Python创建照片马赛克
  • 原文地址:https://www.cnblogs.com/onglublog/p/14736097.html
Copyright © 2011-2022 走看看