zoukankan      html  css  js  c++  java
  • UVA 10795 A Different Task(汉诺塔 递归))

    A Different Task

    epsfbox{p10795a.eps}

    The (Three peg) Tower of Hanoi problem is a popular one in computer science. Briefly the problem is to transfer all the disks from peg-A to peg-C using peg-B as intermediate one in such a way that at no stage a larger disk is above a smaller disk. Normally, we want the minimum number of moves required for this task. The problem is used as an ideal example for learning recursion. It is so well studied that one can find the sequence of moves for smaller number of disks such as 3 or 4. A trivial computer program can find the case of large number of disks also.


    Here we have made your task little bit difficult by making the problem more flexible. Here the disks can be in any peg initially.

    epsfbox{p10795b.eps}

    If more than one disk is in a certain peg, then they will be in a valid arrangement (larger disk will not be on smaller ones). We will give you two such arrangements of disks. You will have to find out the minimum number of moves, which will transform the first arrangement into the second one. Of course you always have to maintain the constraint that smaller disks must be upon the larger ones.

    Input 

    The input file contains at most 100 test cases. Each test case starts with a positive integer N ( 1$ le$N$ le$60), which means the number of disks. You will be given the arrangements in next two lines. Each arrangement will be represented by N integers, which are 12 or 3. If the i-th ( 1$ le$i$ le$N) integer is 1, you should consider that i-th disk is on Peg-A. Input is terminated by N = 0. This case should not be processed.

    Output 

    Output of each test case should consist of a line starting with `Case #' where # is the test case number. It should be followed by the minimum number of moves as specified in the problem statement.

    Sample Input 

    3
    1 1 1
    2 2 2
    3
    1 2 3
    3 2 1
    4
    1 1 1 1
    1 1 1 1
    0

    Sample Output 

    Case 1: 7
    Case 2: 3
    Case 3: 0
    

     题目大意:标准的汉诺塔上有n个大小各异的盘子。给定一个初始局面,求它到达给定目标局面至少需要多少步。

     输入格式:第一行为正整数n,第二行包含n个1-3的整数,即初始局面中每个盒子锁在的柱子编号;第三行和第二行格式相同,为目标局面。

     分析:考虑编号最大的盘子。如果这个盘子在初始局面和目标局面中位于同一根柱子上,那么根本不需要移动它,而如果移动了,反而不可能得到最优解。这样,我们可以在初始局面和目标局面中,找出所在柱子不同的盘子中编号最大的一个,设为k,那么k必须移动。

      让我们设想一下,移动k之前的一瞬间,柱子上的情况。假设盘子k需要从柱子1移动到柱子2.由于编号比k大的盘子不需要移动,而且也不会碍事,所以我们直接把他们看成不存在;编号比k小的盘子既不能在柱子1上,也不能在柱子2上,因此只能在柱子3上。换句话说,这时柱子1只有盘子k,柱子2为空,柱子3从上到下一次是盘子1,2,3,...k-1。我们把这个局面称为参考局面

      由于盘子的移动是可逆的,根据对称性,我们只需要求出初始局面和目标局面移动成参考局面的步数之和,然后加1(移动盘子k)即可。换句话说,我们需要写一个函数f(P,i,final),表示已知各盘子的初始柱子编号数组为P(具体来说,P[i] 代表盘子 i 的柱子编号),把盘子1,2,3,...,i 全部移到柱子final所需的步数,则本题的答案就是  f(start,k-1,6-start[k]-finish[k])+f(finish,k-1,6-start[k]-finish[k])+1。其中start[i]和finish[i]是本题输入中盘子i的初始柱子和目标柱子,k是上面所说的“必须移动的编号最大的盘子”的编号。我们把柱子编号为1,2,3,所以“除了柱子x和柱子y之外的那个柱子”编号为6-x-y。

      如何计算f(P,i,final)?假设P[i]=final,那么f(P,i,final)=f(P,i-1,final);否则需要先把前i-1个盘子挪到6-P[i]-final这个盘子做中转,然后把盘子i移动到柱子final,最后吧前i-1个盘子从中转的柱子移动到目标柱子final。注意,最后一个步骤是把i-1个盘子从一个柱子整体移动到另一个柱子,根据汉诺塔问题的经典结论,这个步骤需要2i-1-1步,加上移动盘子 i 的那一步,一共需要2i-1步。换句话说,当P[i]不等于final的时候f(P,i,final)=f(P,i-1,6-P[i]-final)+2i-1

     代码如下:

     1 #include<cstdio>
     2 
     3 long long f(int* P, int i, int final) {
     4   if(i == 0) return 0;
     5   if(P[i] == final) return f(P, i-1, final);
     6   return f(P, i-1, 6-P[i]-final) + (1LL << (i-1));
     7 }
     8 
     9 const int maxn = 60 + 10;
    10 int n, start[maxn], finish[maxn];
    11 
    12 int main() {
    13   int kase = 0;
    14   while(scanf("%d", &n) == 1 && n) {
    15     for(int i = 1; i <= n; i++) scanf("%d", &start[i]);
    16     for(int i = 1; i <= n; i++) scanf("%d", &finish[i]);
    17     int k = n;
    18     while(k >= 1 && start[k] == finish[k]) k--;
    19 
    20     long long ans = 0;
    21     if(k >= 1) {
    22       int other = 6-start[k]-finish[k];
    23       ans = f(start, k-1, other) + f(finish, k-1, other) + 1;
    24     }
    25     printf("Case %d: %lld
    ", ++kase, ans);
    26   }
    27   return 0;
    28 }
  • 相关阅读:
    二叉树的创建、递归,非递归遍历
    一文读懂PID控制算法(抛弃公式,从原理上真正理解PID控制)
    说走就走的旅行 ——一个人重游长安
    OpenCV笔记:pyrDown()函数和pryUp()函数的使用
    考研心得--一个差劲的ACMer
    HDU 3530 --- Subsequence 单调队列
    POJ 3494 Largest Submatrix of All 1’s 单调队列||单调栈
    极角排序详解:
    POJ 3268 Silver Cow Party 最短路—dijkstra算法的优化。
    给出 中序&后序 序列 建树;给出 先序&中序 序列 建树
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3199754.html
Copyright © 2011-2022 走看看