主题:[原创]汉诺塔
abcwuhang
[专家分:1840] 发布于 2007-07-30 22:27:00
大家都知道汉诺塔吧...(我就不介绍了)游戏是有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.
最后更新于:2007-09-16 18:27:00
回复列表 (共21个回复)
11 楼
小田甜 [专家分:3910] 发布于 2007-08-13 04:02:00
谁能给我的第二个举一个反例?
好像[b]是[/b]最少的呀。
12 楼
游侠UFO [专家分:1200] 发布于 2007-08-13 12:03:00
[quote]谁能给我的第二个举一个反例?
好像[b]是[/b]最少的呀。[/quote]
如果真是这样那不和三塔问题一样了?出这四塔就完全没意义了嘛....
总之四塔问题可以用动态规划来解决
你可以看看这里:全国信息学奥林匹克联赛培训教程(二)/吴文虎,王建德编著.—北京:清华大学出版社,2004年2月第1版 P268 (10)题
13 楼
小田甜 [专家分:3910] 发布于 2007-08-15 15:31:00
关于四棵柱子的汉诺伊塔问题,我受到[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 楼
fly100 [专家分:50] 发布于 2007-08-28 16:44:00
其实此题貌似有些规律:
设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 楼
fly100 [专家分:50] 发布于 2007-08-28 17:10:00
这样一来,程序编写就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 楼
fly100 [专家分:50] 发布于 2007-08-28 17:12:00
可以用数组存,我用循环代替了.....
17 楼
万里长城 [专家分:340] 发布于 2007-09-07 19:26:00
书上递归 6-13
18 楼
无所不能 [专家分:270] 发布于 2007-09-07 21:27:00
苯,让第四个柱子闲下来,不动就行了
19 楼
abcwuhang [专家分:1840] 发布于 2007-09-08 22:30:00
......
怎么总有人看不懂题!
20 楼
fly100 [专家分:50] 发布于 2007-09-09 08:52:00
这题我做过,还在评测系统上交过,就是那样啦!
我来回复