回 帖 发 新 帖 刷新版面

主题:[原创]汉诺塔

大家都知道汉诺塔吧...(我就不介绍了)游戏是有3柱的,其中有一个空闲柱帮助搬运.
大家都知道应该用递归来做吧(我就不讲了)
现在问题是:4柱汉诺塔如何做?(就是:有4个柱子,其中有两个空闲柱,如何移动使其全部移动到另一柱上?(其他规则与原汉诺塔同))


program fourhanoi;
var m:integer;
procedure movetower(n,A,D,C,B:integer);
  procedure moveDisc(fromDisc,toDisc:integer);
  begin
    write(fromDisc,'->',toDisc,' ');
  end;
begin
  if n>0 then
  begin
    movetower(n-2,A,B,D,C);
    moveDisc(A,C);
    moveDisc(A,D);
    moveDisc(C,D);
    movetower(n-2,B,D,C,A);
  end;
end;
begin
  readln(m);
  movetower(m,1,4,3,2);
end.

回复列表 (共21个回复)

11 楼

谁能给我的第二个举一个反例?
好像[b]是[/b]最少的呀。

12 楼

[quote]谁能给我的第二个举一个反例?
好像[b]是[/b]最少的呀。[/quote]

如果真是这样那不和三塔问题一样了?出这四塔就完全没意义了嘛....
总之四塔问题可以用动态规划来解决

你可以看看这里:全国信息学奥林匹克联赛培训教程(二)/吴文虎,王建德编著.—北京:清华大学出版社,2004年2月第1版 P268 (10)题

13 楼

关于四棵柱子的汉诺伊塔问题,我受到[url=http://www.programfan.com/club/member.asp?userid=104518]游侠UFO[/url]的启发,我认为可以写出下面这个转移方程:
f(x)={0    x=0
f(x)={min(0<i<=x){f(x-i)+(2^i-1)}

(这里把所有盘子分成两大块,
首先,如果想要移动一摞到另一棵柱子那里,那么就最少要有3个空位置,
所以,我把利用四棵柱子的移动次数定义为f(x)。
就有,把上面的一摞用四棵柱子移动到另一摞,再把地下一摞用三棵柱子移动到第三摞,最后在把上面的移过去即可。)
程序(仅求次数,TP下编译):
{$N+,R+}
var
  i,j,n:byte;
  f:array [0..255] of longint;
function min(a:longint;b:extended):longint;
begin
  if a<b then min:=a else min:=round(b);
end;
begin
  write('Input n(n>3):');readln(n);
  for i:=1 to n do f[i]:=maxlongint;
  f[0]:=0;
  for j:=1 to n do
    for i:=1 to j do
      f[j]:=min(f[j],2*f[j-i]+exp(ln(2)*i)-1);
  writeln(f[n]);
end.
不知道对不对,还请指教……

14 楼

其实此题貌似有些规律:
设F[I]为3柱的解,G[I]为4柱的解,那么有:
i     1    2    3    4     5    6     7    8      9      10        11 
f[i]  1    3    7    15    31   63  127   255   511     1023      2047 
g[i]  1    3    5    9    13    17   25    33    41      49       65 
观察这个表,我们可以大胆地猜想g[i]的规律:从1开始,加2次2,再加3次4,再加4次8,再加5次16……显然,g[2]是用g[1]和f[1]算出来的。
亲手模拟一下g的计算过程,就会发现,g数列加2^k的次数等于g数列加2^(k-1)的次数与f数列加2^k的次数之和。由此可以得出上面的猜想。
   这个问题可以推广到m塔的情况。用a[i]表示m柱i盘时所需的移动次数,则a数列有这样一个规律: a[1]=1,以后依次有C(M-3+K,M-3)项比前一项大2^k,其中k从1开始取整数值。 

15 楼

这样一来,程序编写就OK了:
var
 a,b:longint;
 i,j,n,k,t:longint;
begin
 readln(n);
 b:=1;
 j:=2; t:=3;
 i:=2; k:=2;
 while i<=n do
  begin
   a:=b+j;
   b:=a;
   dec(k);
   if k=0 then
    begin
     k:=t;
     t:=t+1;
     j:=j*2;
    end;
   inc(i);
  end;
 writeln(a);
end.

16 楼

可以用数组存,我用循环代替了.....

17 楼

书上递归 6-13



















































































































18 楼

苯,让第四个柱子闲下来,不动就行了

19 楼

......
怎么总有人看不懂题!

20 楼

这题我做过,还在评测系统上交过,就是那样啦!

我来回复

您尚未登录,请登录后再回复。点此登录或注册