A Different Task |
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.
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.
The input file contains at most 100 test cases. Each test case starts with a positive integerN ( 1N60), which means the number of disks. You will be given the arrangements in next two lines. Each arrangement will be represented byN integers, which are 1, 2 or 3. If the i-th (1iN) integer is1, you should consider that i-th disk is on Peg-A. Input is terminated byN = 0. This case should not be processed.
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.
3 1 1 1 2 2 2 3 1 2 3 3 2 1 4 1 1 1 1 1 1 1 1 0
Case 1: 7 Case 2: 3 Case 3: 0
给出初始状态和结束状态,问最少需要多少步完成。
话说各种汉诺塔问题。。都很难想。。这个题的出发点是先找到初始状态和结束状态在不同柱子上的最大编号的盘子,比这个编号大的在同一个柱子上的肯定不用移动,可以直接当作不存在。设这个编号最大的盘子编号k,初始在柱子1,结束时在柱子2,那么肯定是先要把编号1...k-1共k-1个盘子移动到3,再把这个k移动到2。设这个把1...k-1个盘子移动到3这个必经状态为中间状态,那么答案是不是就等于从初始状态到中间状态的步数加上1(把k移动到2)再加上中间状态移动到结束状态的步数。由于过程可逆,中间状态移动到结束状态的步数也等于结束状态移动到中间状态的步数。设f(p,k,c)为处在状态p,要把编号1...k的盘子移到c柱子上的步数。一开始找到最大的k,最终答案就为f(start,k-1,other)+f(finish,k-1,other)+1,other是初始和结束k所在之外的那个柱子,other=6-start[k]-finish[k]。以前没发现这个简单的表示方法,总是递归传参的时候交换柱子,其实用6减是个好办法啊。。
f函数,若p[k]==c,k盘子不用移动,那么f(p,k,c)=f(p,k-1,c)。否则若k不为0,要先把k-1个盘子移到另一个柱子,把k移到c,再把k-1个移到c。把k移到c,再把叠好的k-1个移到c这个过程需要2^(k-1)-1+1=2^(k-1)次, f(p,k,c)=f(p,k-1,6-p[k]-c)+2^(k-1)。
注意long long。
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<map> #define INF 0x3f3f3f3f #define MAXN 70 #define MAXM 20010 #define eps 1e-9 #define pii pair<int,int> using namespace std; int N,start[MAXN],finish[MAXN]; long long f(int *p,int k,int c){ if(!k) return 0; if(p[k]==c) return f(p,k-1,c); return f(p,k-1,6-p[k]-c)+((long long)1<<(k-1)); } int main(){ freopen("in.txt","r",stdin); int cas=0; while(scanf("%d",&N),N){ int i; for(i=1;i<=N;i++) scanf("%d",&start[i]); for(i=1;i<=N;i++) scanf("%d",&finish[i]); int k=N; while(k>=1&&start[k]==finish[k]) k--; long long ans=0; if(k>=1){ int other=6-start[k]-finish[k]; ans=f(start,k-1,other)+f(finish,k-1,other)+1; } printf("Case %d: %lld\n",++cas,ans); } return 0; }