Towers of Hanoi |
In 1883, Edouard Lucas invented, or perhaps reinvented, one of the most popular puzzles of all times - the Tower of Hanoi, as he called it - which is still used today in many computer science textbooks to demonstrate how to write a recursive algorithm or program. First of all, we will make a list of the rules of the puzzle:
A good way to get a feeling for the puzzle is to write a program which will show a copy of the puzzle on the screen and let you simulate moving the disks around. The next step could be to write a program for solving the puzzle in a efficient way. You don't have to do neither, but only know the actual situation after a given number of moves by using a determinate algorithm.
It is well known and rather easy to prove that the minimum number of moves needed to complete the puzzle withn disks is . A simple algorithm which allows us to reach this optimum is as follows: for odd moves, take the smallest disk (number 1) from the peg where it lies to the next one in the circular sequence ; for even moves, make the only possible move not involving disk 1.
The input file will consist of a series of lines. Each line will contain two integersn, m: n, lying within the range [0,100], will denote the number of disks andm, belonging to [0, ], will be the number of the last move. The file will end at a line formed by two zeros.
The output will consist again of a series of lines, one for each line of the input. Each of them will be formed by three integers indicating the number of disks in the pegsA, B and C respectively, when using the algorithm described above.
3 5 64 2 8 45 0 0
1 1 1 62 1 1 4 2 2
汉诺塔。。这个很是有点坑啊。。给你盘子的个数和移动的步数,问此时的盘子的状态。
移动完成n个盘子的汉诺塔需要2^n-1步,可以想到2进制,n个1。假设把A的盘子移到C。那么先把n-1个盘子移到B,需要2^(n-1)-1步,再把A上最下面的盘子移到C,要一步。也就是通过2^(n-1)次移动就完成了最大的盘子到C,并且其他盘子都在B上。换成2进制就是最高位是1。现在就变成了n-1个盘子同样的问题,只是要从B移动到C,也就是A盘和B盘交换了。但是如果移动的步数少于2^(n-1),最下面的盘子就没有被移动,状态就成了要把n-1个盘子移动到B,此时把B盘和C盘交换。
所以思路就是把步数换成2进制,递归做。从n-1位开始(最高位时盘子数是总数N个,每判断一位就能确定一个盘子的位置,所以每减少一位操作的盘子数减1,设为n),判断每一位是1还是0。如果是1,A的最底下的盘子就移动到C,把n-1个盘子移动到B,接着递归(A和B交换位置)。如果是0,A最底下的就不动,接着递归(B和C交换位置)。
这道题第一坑的是还要写个大数除以2的除法来求出2进制(每步最后的余数存到数组里),第二坑是他不是要求最后完成是放到C上,而是第一步放B上,所以有偶数个盘子的时候最后是全放在C上,有奇数个盘子的时候是最后全在B上。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cctype> #include<algorithm> #define INF 0x3f3f3f3f using namespace std; int ans[5],b[130]; char str[130]; void binary(){ int i,p=0,k=0,l,a[130]; memset(b,0,sizeof(b)); l=strlen(str); for(i=0;i<l;i++) a[i]=str[i]-'0'; while(p<l){ int mod=0; for(i=p;i<l;i++){ a[i]=mod*10+a[i]; mod=a[i]&1; a[i]>>=1; } b[k++]=mod; if(!a[p]) p++; } } void hanoi(int A,int B,int C,int k){ if(k<=0) return; if(b[k-1]){ ans[A]-=k; ans[B]+=k-1; ans[C]++; hanoi(B,A,C,k-1); } else hanoi(A,C,B,k-1); } int main(){ // freopen("in.txt","r",stdin); int N; while(scanf("%d%s",&N,str),N||str[0]!='0'){ binary(); ans[0]=N; ans[1]=0; ans[2]=0; if(N%2) hanoi(0,2,1,N); else hanoi(0,1,2,N); printf("%d %d %d\n",ans[0],ans[1],ans[2]); } return 0; }