HDU4260
来源:互联网 发布:淘宝修改评价链接 编辑:程序博客网 时间:2024/06/07 14:53
Problem: The End of The World
Description: 汉诺塔问题变形。给你一串字符串,第一个字符代表着第一小的那个盘子所在的柱子,以此类推。问你最少要多少步才能把所有的盘子移到B柱子。
Solution: 递归。这个递归我一开始也不是很明白,后来仔细想想确实是这样。递归的过程其实如同解决普通的汉诺塔问题是一样的。都是把前N个盘子移动到某根柱子。这个时候你可能会有疑虑了,盘子并不是都分布在一根柱子上,那么我们把前N个盘子移动到一根柱子上会不会进行地这么顺利(也就会说会不会出现大盘子放到小盘子上)。其实不会。你反过来想想就知道了,我们先把最小的盘子移动到次小的盘子上这是一定可以做到的。因为汉诺塔的规则就是这样(大在下小在上)。那么我们肯定可以把次小以上的移动到第三小的上,以此类推。那么我们这个递归的过程不就是顺着来的过程的一个逆吗?于是写出代码,先把前N-1个盘子移动到辅助的柱子上,再把第N个盘子移动到B柱子上,最后把辅助柱子上有顺序而且紧密的柱子集移动到B柱子。这样子就完成了。
Code(C++):
#include <stdio.h>#include <string.h>#define LL long longconst int M=70;LL dp[64];char str[M];void get_one_step(){ dp[0]=0; dp[1]=1; for(int i=2;i<64;i++) dp[i]=2*dp[i-1]+1;}LL work(int order,char to){ if(!order) return 0; char now=str[order-1]; switch(now){ case 'A': // 如果在目的盘子就把order-1根柱子全部移动到目标柱子 if(to=='A') return work(order-1,to); // 如果不在。那么根据情况把order-1根柱子移动到辅助柱子,再把目的牌子移动到目的柱子,最后再把有序紧密的order-1根柱子全部移动到目的柱子 else if(to=='B') return work(order-1,'C')+dp[order-1]+1; else if(to=='C') return work(order-1,'B')+dp[order-1]+1; case 'B': if(to=='A') return work(order-1,'C')+dp[order-1]+1; else if(to=='B') return work(order-1,to); else if(to=='C') return work(order-1,'A')+dp[order-1]+1; case 'C': if(to=='A') return work(order-1,'B')+dp[order-1]+1; else if(to=='B') return work(order-1,'A')+dp[order-1]+1; else if(to=='C') return work(order-1,to); } return 0;}int main(){ get_one_step(); //get_two_step(); while(~scanf("%s",str),str[0]!='X'){ LL ans=work(strlen(str),'B'); printf("%lld\n",ans); } return 0;}
后来又看了网上其他人的解题代码。发现唯一不同的就是他在计算把第N个盘子移动到目标柱子和把前N-1个盘子移动到目标柱子写到了一起,也就是写成了(1LL<<(order-1)),代替了我的dp[order-1]+1。这样为什么也可以呢。后来我想起了高中常解的等比数列的题目,我们看看递归的这个公式:
#include <stdio.h>#include <string.h>#define LL long longconst int M=70;LL dp[64];char str[M];void get_two_step(){ dp[0]=1; LL power=1; for(int i=1;i<64;i++,power<<=1) dp[i]=2*power;}LL work(int order,char to){ if(!order) return 0; char now=str[order-1]; switch(now){ case 'A': if(to=='A') return work(order-1,to); else if(to=='B') return work(order-1,'C')+dp[order-1]; else if(to=='C') return work(order-1,'B')+dp[order-1]; case 'B': if(to=='A') return work(order-1,'C')+dp[order-1]; else if(to=='B') return work(order-1,to); else if(to=='C') return work(order-1,'A')+dp[order-1]; case 'C': if(to=='A') return work(order-1,'B')+dp[order-1]; else if(to=='B') return work(order-1,'A')+dp[order-1]; else if(to=='C') return work(order-1,to); } return 0;}int main(){ //get_one_step(); get_two_step(); while(~scanf("%s",str),str[0]!='X'){ LL ans=work(strlen(str),'B'); printf("%lld\n",ans); } return 0;}
0 0