看了一下杭电的各种汉诺塔问题,遇到些奇奇葩葩的小问题,也有很多很好的思想,比如最后一题,来来回回的颠倒很有意思。总结一下;

Pro.ID 1207 :http://acm.hdu.edu.cn/showproblem.php?pid=1207

意思是给把原始的汉诺塔问题中的3根柱子改为4根。做了半天各种WA。查了一下,有一篇文章详细讲了一下,还做出了递归公式以及数学公式:

地址如下:http://www.cnblogs.com/fanzhidongyzby/archive/2012/07/28/2613173.html.

代码如下:

#include<cstdio>
#include<cmath>
#include<algorithm>
//F(n)=min(2*F(n-r)+2^r-1),(1≤r≤n)
using namespace std;
int main()
{int n,m;long long Min,f[65];f[1]=1;f[2]=3;for(int i=3;i<=65;i++){Min=99999999;for(int j=1;j<i;j++)Min=min(2*f[j]+pow(2.0,i-j)-1,Min*1.0);f[i]=Min;}while(~scanf("%d",&n))printf("%lld\n",f[n]);return 0;
}

按照公式写就是了,写的时候需要注意一下精度问题。2^r可以写为1<<r,不过因为数字常数1默认是32位,所以如果要使用位移的话,一定要先声明一个longlong类型的变量来进行位移,否则 就会出现溢出错误,这个我纠结了一阵子,感觉没错,一提交就WA,然后试了试64发现果然是负数。

哎,基础还是不扎实啊。

用pow函数因为返回的是一个double类型,min函数里比较也是用double来做的,只是在最后赋值的时候取int型就可以,所以不会出错。

Pro.ID  1995 汉诺塔V

http://acm.hdu.edu.cn/showproblem.php?pid=1995

这个是普通的汉诺塔,最优的步数是2^n-1,只不过问的第i个盘子移动的次数。依然是用递归,在纸上画画就能出来。

注意了,第i盘子,不用考虑底下的盘子,只用看之上的经过一个柱子到达目的地。即F[n]=2*f[n-1]

代码:

#include<iostream>using namespace std;int
main()
{__int64 s[61] = {0, 1};int n, i, t, m;for(i = 2; i < 61; i++)s[i] = s[i - 1] * 2;cin >> t;while(t--){cin >> n >> m;cout << s[n - m + 1] << endl;}
}

Pro.ID 汉诺塔VI

http://acm.hdu.edu.cn/showproblem.php?pid=1996

是问所有步骤,注意不是最优的,是全部(当然不包括错误的步骤)

每一个盘子可以放到3根柱子的任意一个,所以是3^n。比如正确的是直接从a->c,现在可以a->b然后在b->c,就是多了2种。每一个都多了2种,所以是3^n。

代码:

#include<iostream>
#include<math.h>
#include<stdio.h>
using namespace std;
int main()
{__int64 t,n,i;__int64 sum,a[100]={3,};while(cin>>t)while(t--){cin>>n;for(i=1;i<n;i++)a[i]=a[i-1]*3;cout<<a[n-1]<<endl;}return 0;
}

Pro.ID 1997 汉诺塔VII

http://acm.hdu.edu.cn/showproblem.php?pid=1997

题目是说,给定某一时刻的三个柱子上的盘子,问这个是不是符合最优解过程中某一时刻的状态。

思想是:

对一个含有n个盘子,从A柱移动到C柱借助B柱的汉诺塔,第n个盘子移动到C柱过程是这样子的:首先将其余的n-1个盘子移动到B柱,然后第n个盘子直接移动到C柱。在这过程中,第n个盘子只出现在A柱和C柱两个柱子上,也即第n个盘子不可能出现在B柱上。因此对于当前移动的盘子,只需检查其所在的柱子是否符合这个要求,如果出现在B柱上,则显然进入了错误移动中。这是本题求解思想精髓所在。

具体的内容请参考这篇博客:http://blog.csdn.net/z690933166/article/details/8605261

代码就不贴了,上边这个博客里写的很详细。

Pro.ID 2064 汉诺塔III

http://acm.hdu.edu.cn/showproblem.php?pid=2064

还是递推:num[i]=3*num[i-1]+2;

不解释了,代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
unsigned long long num[36];
int main()
{              num[1]=2;num[2]=8;for(int i=3;i<=35;i++)num[i]=3*num[i-1]+2;int n;while(~scanf("%d",&n))cout<<num[n]<<endl;return 0;
}

Pro.ID 2077 汉诺塔IV(参考了 zz_zigzag的博客)

http://acm.hdu.edu.cn/showproblem.php?pid=2077

好无聊啊,把上边的规则给改了,只是最大的可以放上边。其实感觉这个题目跟之前那个1027题目有点想通之处,在1027中说的是4根柱子,所以通用的这3个步骤其实并非最优解:

(1)       从1柱借助3…M柱子将n-(M-2)个盘子移动到2柱上。

(2)       将M-2个通过3…M-1柱简单的移动到M柱上【2*(M-2)-1步骤】。

(3)       从2柱借助1,3…M-1柱子将n-(M-2)个盘子移动到M柱上。

如果有n个盘子,则需要前n-1个挪到中间的盘子上,然后最大的盘子挪到最右面,需要两步,把前(n-1)个盘子从左边挪到中间是和从中间挪到右边需要相同的次数。而a数组中存放的就是那个前n-1个盘子挪动到相同位置需要的次数。结果即为a[i-1]*2+2。

所以我直接想成了是f[n]=2*f[n-1]+2,结果错了。【因为是需要n-1个盘子前进一步】

而求a数组需要用到递推。公式为第i个为前n-1个移动次数的三倍加一,简化到两个盘子,小的先移动两次到最右边,大的移到中间,然后小的在移回中间,小的移动了三次,而大的移动了一次,就使他们全部挪动了一个位置

所以代码如下:

#include<stdio.h>
int a[20]={0,1};int main()
{int i,T;for(i=2;i<21;i++){a[i]=3*a[i-1]+1; }scanf("%d",&T);while(T--){scanf("%d",&i);printf("%d\n",2*a[i-1]+2);}return 0;
}

Pro.ID 2175 汉诺塔IX

http://acm.hdu.edu.cn/showproblem.php?pid=2175

普通汉诺塔,问在最优步骤中的第i步是哪一个盘子,跟1995那个题目刚好相反。不过这个有点像数论题。

这样想,假设是4个盘子,考虑第三个,在第4步的时候将3盘从A移动到C【设目的地是B】,此时1,2盘在B上,设时间为T,然后将1,2盘移动到C上,(需要3步)再把4盘移动到B上,此时的格局为4盘在B上,1,2,3,在C上,距T过去了1+3=4步,那么3号盘什么时候再动呢?把1,2移走,3就可以放到B上了,移走1,2需要花费3个步骤,因此距T4+3+1也就是第8步,总体是第12步时,3号盘子会再次移动。现在看明白了吧,就是基数倍的2^(i-1)时,i号盘子会移动。

代码如下:

#include<iostream>
using namespace std;
int main()
{__int64 a[65];a[1]=1;__int64 i,n,r;__int64 m;for(i=2;i<=63;i++)a[i]=2*a[i-1];while(~scanf("%I64d%I64d",&n,&m),n+m){for(i=1;i<=n;i++){r=m/a[i];if(r%2==1&&m%a[i]==0)printf("%I64d\n",i);}}return 0;
}

Pro.ID 2184 汉诺塔VIII

感觉这个题目非常的好,挺有意思的,问普通汉诺塔,N个盘子,在最优解的第M步时,每个柱子上的盘子的状态。

想了半天,也没什么思路,但有一点是绝对可以确定的,就是一般解简单汉诺塔过程的问题都是使用递归,可以得到全部过程,但是当N稍微到10以上的时候必然递归很慢,所以直接递归模拟必然是错误的,但是根据上一题目,第i个步移动哪一个盘子中确定的,第K个盘子在  奇数*2^(K-1)时移动可以得到些思想,必然是根据步数来确定盘子。

但是想了老半天也不太清楚那个递归改怎么写,好像每一次判断都要做除法到是可以确定某一个盘子,但是如何确定所有的盘子呢?纠结啊

查了半天,找到了一个大神的代码。

地址在:http://blog.lchx.me/index.php/hdu-2184-%E6%B1%89%E8%AF%BA%E5%A1%94viii/

讲的非常的详细,我把思路以及代码粘过来大家分享一下:

/*定义数组a,其中a[i]表示完成一次i层汉诺塔移动的次数。
指针o,p,q分别表示三个位置。
起始状态为n层都在o上,要往q方向移动。
然后分成两种情况:
1、
m<=a[n-1];
此时,第n层没机会移动,那么就相当于o上的n-1层往p上移动。
使其状态和起始状态一致,我们要交换p和q。
2、
m>a[n-1];
此时,先进行到下面状态,上面n-1层移动到p位置,第n层移动到q位置,消耗了a[n-1]+1次移动。
接下来就变成p上的n-1层往q上移动,只要交换o,p,令m=m-a[n-1]-1即可。通过上述操作,都可以得到第n层的位置,并且问题变成n-1层都在o上,要往q方向移动。
*/
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int main()
{unsigned __int64 m,a[64];int row[3][66];a[1]=1;a[0]=0;for(int i=2;i<=63;i++)a[i]=a[i-1]*2+1;int t;scanf("%d",&t);while(t--){int n;scanf("%d %I64u",&n,&m);int *start,*mid,*end;start=row[0];mid=row[1];end=row[2];*start=*mid=*end=1;while(n){n--;if(m<=a[n]){*(start+*start)=n+1;//从第二个位置开始记录盘子(*start)++;//第一个位置表示的是这个柱子一共有多少个盘子swap(end,mid);}else{*(end+*end)=n+1;(*end)++;swap(start,mid);m-=(a[n]+1);}      }for(int i=0;i<3;i++){printf("%d",row[i][0]-1);for(int j=1;j<row[i][0];j++)printf(" %d",row[i][j]);printf("\n");}}return 0;
}

Pro.ID 汉诺塔 X

http://acm.hdu.edu.cn/showproblem.php?pid=2511

进一步加强条件,在求第m步时是哪个盘子动,怎么动。

必然递归啊。把上上个题目修改就可以了。具体的就不多说了,在注释里有详细解释

#include<iostream>
using namespace std;__int64 a[65];
void solve(int n,__int64 m,int start,int end)
{int third=6-start-end;//得到第3跟柱子__int64 mid=a[n];if(m==mid) //如果是当前盘子移动,直接从start-->end{printf("%d %d %d\n",n,start,end);return ;}if(m<mid)//当前盘子无法移动,必然是上边的某个盘子动,并且移动一定是到third号柱子上,递归求解solve(n-1,m,start,third);else//需要先移动当期盘子下部的盘子(参考2184题目)solve(n-1,m-mid,third,end);
}int main()
{__int64 m;a[1]=1;int n;for(int i=2;i<=63;i++)a[i]=2*a[i-1];int t;while(~scanf("%d",&t)){while(t--){scanf("%d%I64d",&n,&m);solve(n,m,1,3);}}return 0;
}

最后一个Pro.ID  2587:很O_O的汉诺塔

http://acm.hdu.edu.cn/showproblem.php?pid=2587

真心是跪了,

感谢hr_whisper的详细讲解,这里已经写的很清楚了:http://blog.csdn.net/murmured/article/details/9943947

杭电 汉诺塔问题总结相关推荐

  1. 杭电_ACM_汉诺塔VII

    Problem Description n个盘子的汉诺塔问题的最少移动次数是2^n-1,即在移动过程中会产生2^n个系列.由于发生错移产生的系列就增加了,这种错误是放错了柱子,并不会把大盘放到小盘上, ...

  2. 汉诺塔相关介绍及计算

    汉诺塔的相关题目及计算 汉诺塔的相关介绍及分析 简介 经典汉诺塔 求最小移动次数 汉诺塔的相关介绍及分析 简介 前两天无意中提到了汉诺塔就重新刷了一下相关的题目,感觉有些题目有很多巧妙之处,提到汉诺塔 ...

  3. 汉诺塔(三)_栈的应用

    问题 E: 汉诺塔(三) 时间限制: 3 Sec  内存限制: 128 MB 提交: 2  解决: 2 [提交][状态][讨论版] 题目描述 在印度,有这么一个古老的传说:在世界中心贝拿勒斯(在印度北 ...

  4. 汉诺塔怎么加计数次数c语言,C语言计算汉诺塔最小移动步数 (二)

    前几天写的:C语言计算汉诺塔最小移动步数(一) 当时还不知道用2^n-1这个公式来求解汉诺塔移动步骤.=_= 偶然间在网上发现了这个公式,发现当时写的算法还是比较繁琐的.所以又根据这个公式又写了一个. ...

  5. Ka的递归编程练习 Part4|Hanoi汉诺塔,双色汉诺塔的也有

    1 #include <stdio.h> 2 void hanoi(int s,char a,char b,char c) //a是出发盘,b是中途盘,c是结束盘 3 { 4 if(s== ...

  6. 技术图文:如何实现汉诺塔问题?

    背景 最近在辅导小孩们学习编程,在介绍函数递归时,最典型的就是汉诺塔问题了. 我在这里总结一下,以方便大家的学习. 汉诺塔问题源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在 ...

  7. 汉诺塔问题---小昝

    C语言 #include <stdio.h> void move(char A,char C){printf("%c ---> %c\n",A,C); }void ...

  8. 轻松理解汉诺塔问题(图解java描述)

    引言:(易于理解) 汉诺塔看似简单的几行代码,却蕴含着奇妙的算法.我从我个人学习的角度来说.我一开始理解了原理,但是编码不会编,这也就是所谓的眼高手低.多研究多在IDE(eclipse-java,VS ...

  9. 栈与队列5——汉诺塔问题(方案二)

    题目 汉诺塔问题的基础上,增加限制,必须得经过中间,不能直接从左到右或从右到左,求当塔有N层的时候打印最优移动过程和最优移动总步数 要求 法一:递归法 法二:非递归法,用栈来模拟 解析 法二:非递归法 ...

最新文章

  1. 日志服务商业化计费FAQ和账单优化
  2. 【Linux】一步一步学Linux——bg命令(131)
  3. c语言编译器怎样退出全屏,BOOX 应用软件怎样退出全屏模式?
  4. element tree不刷新视图_Vue项目布署后,刷新页面404的真正原因找到了
  5. 我是程序员,我用这种方式铭记历史
  6. mysql支持事务的存储引擎_MySQL基础(三)【MySQL事务与存储引擎】
  7. cnn加工是什么意思_天秤座R-CNN:全面平衡的目标检测器
  8. 如何下载B站视频到本地?
  9. 如何将ffmpeg在windows编译和使用
  10. 程序员的自我修养(序)-量子
  11. K-Lite Codec Pack 解码器下载及安装过程步骤参考
  12. 读取mysql表名称_JAVA动态读取mysql表的字段名索引
  13. Maven发布工程到公共库
  14. 关于websocket长链接的使用
  15. PHP生成二维码与识别二维码
  16. iPad 隐藏按钮获取函数
  17. 深度学习模型---稀疏编码 Sparse Coding
  18. 试用Windows Server 2008
  19. Python 学习资源大全中文版
  20. Unity-协成-开启关闭

热门文章

  1. 整型和浮点型的区别_C的基础内容:常量之数值型常量,适合新手的学习
  2. Eclipse搭建SpringCloud+SSM+Maven项目
  3. 局域网读取文件_教你windows局域网如何设置共享文件
  4. 计算机mac地址里面0,如何查计算机MAC地址
  5. inline-block什么意思中文_css中inline-block是什么?inline-block布局的使用
  6. 关于documentFrgament 文档片段的简单理解
  7. React Native debug debugger
  8. C语言复习2_运算符
  9. 学习OpenGL:笔记一
  10. VBA编程常用词汇英汉对照表