A Different Task

来源:互联网 发布:js继承是什么 编辑:程序博客网 时间:2024/05/15 03:22
\epsfbox{p10795a.eps}
Description

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

31 1 12 2 231 2 33 2 141 1 1 11 1 1 10

Sample Output

Case 1: 7Case 2: 3Case 3: 0
首先我们先回顾一下经典的汉诺塔问题。经典的汉诺塔问题是把n个盘子从某一位置全部移动到另一位置,用到递归的思想。代码如下:
#include<iostream>using namespace std;void hanoi(int n,char A,char B,char C){if(n==1) printf("MOVE disk %d from %c to %c\n",n,A,C);else{hanoi(n-1,A,C,B);printf("MOVE disk %d from %c to %c\n",n,A,C);hanoi(n-1,B,A,C);}}int main(){int n;cin>>n;hanoi(n,'A','B','C');return 0;}
而且我们可以得出结论,对于经典的汉诺塔问题,移动n个盘子总共需要:2^(n-1 )-1步。
对于这道题,我们不需要把所有的盘子都移动到某一位置,而是移动到特殊的位置。显然还是一个递归的问题,对于递归,我个人觉得找到规律和控制结束条件是关键。因为这道题是求解的移动到指定位置所需的最少步数,所以我们可以这样考虑,初始位置和最终位置不一致的序号最大的盘子(比如k)是我们必须移动的盘子。假设我们最终要把k从1移动到2,我们只需要把k-1个盘子移动到3,再把k移动到2就可以了。由于移动是可逆的,所以把k-1个盘子从初始位置移动到3所需的步数=把k-1个盘子从最终位置移动到3所需的步数。我们用d_hanoi(p,n,finish)表示把n个盘子从初始位置(p是记录起始位置的数组)移动到所需位置的步数。则把所有盘子移动到最终位置所需的步数=d_hanoi(start,k-1,sit)+d_hanoi(final,k-1,sit)+1。sit是除了k开始所在的柱子和k最终要到的柱子之外的柱子,即6-start【k】-final【k】
下面说一下d_hanoi这个函数。d_hanoi(int *p,n,sit) 如果n=0,说明所有盘子移动好了,return 0就可以了;如果这些盘子中最大的盘子本来就在我们需要他到达的位置,我们就不需要移动他,只需移动比他序号小的盘子,即return d_hanoi(p,n-1,sit);如果所有的盘子都不在我们需要他们在的位置,那我们就需要先把这n-1个盘子全部移动到某一柱子,再把第n个移动到指定位置,再把n-1个全部移动到指定位置(这一步是经典汉诺塔问题,需要2^(n-1)+1步 ),即返回d_hanoi(p,n-1,6-p[n]-sit)+2^(n-1)-1+1。代码如下:
#include<iostream>#include<cstdio>using namespace std;int start[65];int final[65];long long int d_hanoi(int *p,int n,int sit)    //注意这里是long long int因为最多有60个盘子{if(n==0) return 0;if(p[n]==sit) return d_hanoi(p,n-1,sit);return d_hanoi(p,n-1,6-p[n]-sit)+(1LL<<(n-1));}int main(){int n,count=0;while(scanf("%d",&n)==1&&n){long long int time;  //注意类型for(int i=1;i<=n;i++) cin>>start[i];for(int i=1;i<=n;i++) cin>>final[i];int k=n;while(k>=1&&(start[k]==final[k])) k--;printf("Case %d:",++count);if(k==0) cout<<" 0"<<endl;else{int finish=6-start[k]-final[k];time=d_hanoi(start,k-1,finish)+d_hanoi(final,k-1,finish)+1;cout<<" "<<time<<endl;}}return 0;}



0 0
原创粉丝点击