http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=456&page=show_problem&problem=1736
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 are1, 2 or 3. If the i-th (1iN) integer is 1, 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,因为如果最大的盘子在目标柱子上它不需要移动,也不碍事。
因此问题就成了把k移动到目标柱子,把1到(k-1)移动到中转柱子,所以假设k从A移动到B,A只有k,B是空的,C上面是1到(k-1),把这个局面称为参考局面。因为移动是对称的,所以从参考局面移到目标局面与目标局面移到参考局面是一样的步数。
所以我们只需要求出初始局面和目标局面移动成参考局面的步数之和,然后加1(移动盘子k)即可。
我们需要写一个函数f(P,i,final),表示已知个盘子的初始柱面编号数组为P,把1到i移动到final的步数,据此本题答案表示为f(start,k-1,start[k]^finish[k])+f(finish,k-1,start[k]^finish[k])+1(技巧:1^2=3,1^3=2,2^3=1)
下面计算f(P,i,final)。若p[i]=final,则f(P,i,final)=f(P,i-1,final);否则,需要把前i-1个盘子挪到中转盘去,将盘子i移到柱子final去,最后把前i-1个盘子从中转盘移到柱子final(最后一步是把i-1个盘子从一个柱子移到另一个柱子,根据旧汉诺塔问题,这个步骤需要2^(i-1)-1步,加上移动盘子i那一步,一共需要2^(i-1)步),故有f(P,i,final)=f(P,i-1,p[i]^final)+2^(i-1)
PS:此题可以参考《具体数学》第一章习题4
完整代码:
/*0.019s*/ #include<cstdio> const int maxn = 65; int n, start[maxn], finish[maxn]; long long f(int* P, int i, int final) { if (i == 0) return 0; if (P[i] == final) ///表示这个盘子已经到位了 return f(P, i - 1, final); return f(P, i - 1, P[i] ^ final) + (1LL << (i - 1)); } int main() { int kase = 0; while (scanf("%d", &n), n) { for (int i = 1; i <= n; i++) scanf("%d", &start[i]); for (int 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) ans = f(start, k - 1, start[k] ^ finish[k]) + f(finish, k - 1, start[k] ^ finish[k]) + 1; printf("Case %d: %lld\n", ++kase, ans); } return 0; }