(Translated by https://www.hiragana.jp/)
汉诺塔 - 维基百科,自由的百科全书 とべ转到内容ないよう

汉诺とう

本页使用了标题或全文手工转换
维基百科ひゃっか自由じゆうてき百科ひゃっかぜん
つね玩具おもちゃばん汉诺とうゆう8个圆盘
3个圆盘的汉诺とうてきうつり
4个圆盘的汉诺とうてきうつり

汉诺とうみなとだいかわ內塔)(Tower of Hanoi)すえ一个传说形成的數學问题:

ゆう三根みつね杆子A,B,C。A杆上ゆう N 个 (N>1) 穿孔せんこう圆盘,盘的尺寸しゃくすんよしいたじょう变小。要求ようきゅう按下れつ规则しょう所有しょゆう圆盘うつりいたり C 杆:

  1. 每次まいじただのううつり动一个圆盘;
  2. だい不能ふのう叠在しょう盘上めん

提示ていじしょう圆盘临时おけ于 B 杆,也可はた从 A 杆移出いしゅつてき圆盘おもしんうつりかい A 杆,ただし必须遵循上述じょうじゅつ两条规则。

问:如何いかうつり最少さいしょうよううつり多少たしょう

这里ゆう汉诺とうざい线页めん以来いらいからだ验汉诺塔,以设おけ不同ふどう层数,也可以获さい优移动提示ていじかい。该在线游戏支持しじ任意にんいはつはじめじょう态获さいけいうつり动路みち

传说

[编辑]

最早もはや發明はつめい這個問題もんだいてきじんほうこく數學すうがくあいとくはな·卡斯

傳說でんせつこしみなみ河内かわうちぼうあいだ寺院じいんゆうさんぎんぼううえくし 64 个金ばん寺院じいんうらてきそう侶依あきらいち古老ころうてき預言よげん以上いじょうじゅつ規則きそく移動いどう這些ばん預言よげんせつとう這些ばん移動いどうかん毕,世界せかい就會滅亡めつぼう。這個傳說でんせつさけべ梵天ぼんてんてらとう問題もんだい(Tower of Brahma puzzle)。ただし不知ふちどう卡斯そうてき這個傳說でんせつかえ他人たにん啟發けいはつ

わか傳說でんせつぞくそう侶們需要じゅよう 才能さいのう完成かんせい這個任務にんむわか每秒まいびょう完成かんせいいちばんてき移動いどう,就需要じゅよう 5849 おくねん才能さいのう完成かんせいせい宇宙うちゅう現在げんざい也不 137 おくねん

這個傳說でんせつゆう若干じゃっかん變體へんたい寺院じいんかわなる修道院しゅうどういんそう侶換なり修士しゅうしとうとう寺院じいんてき地點ちてん眾說まがえ紜,其中一說是位于越南的河內,所以ゆえん命名めいめいためかわ內塔」。另外またゆうかねばん創世そうせいどきしょづくり」、「僧侶そうりょ們每てん移動いどういちばんこれるいてき背景はいけい設定せってい

解答かいとう

[编辑]

如取 N=64,最少さいしょう需移动 264−1 そく如果一秒钟能移动一块圆盘,仍需 5849 おくねん目前もくぜん按照宇宙うちゅうだいばく炸理ろんてき推测,宇宙うちゅうてき年齡ねんれい僅為 137 おくねん

ざい实玩ちゅう一般いっぱん N=8;最少さいしょう需移动 255 。如果 N=10,最少さいしょう需移动 1023 。如果N=15,最少さいしょう需移动32767;这就说,如果いち个人从 3 岁到 99 岁,まいてんうつり动一块圆盘,最多さいた仅能うつり动 15 块。如果 N=20,最少さいしょう需移动 1048575 そくちょう过了いちひゃくまん

算法さんぽうもとめかい

[编辑]

解法かいほうてき基本きほん思想しそう递归。かり设有 A、B、C さん个塔,A とうゆう 块盘,もく标是这些盘全うつりいた C とう么先 A とう顶部てき 块盘うつり动到 B とうさい A とうあましたてきだい盘移いた C,さいきさき B とうてき 块盘うつりいた C。

如此递归使用しよう, 就可以求かい

遞迴かい

[编辑]

ざい Javaげんちゅう

public class HW {
	public static java.util.Scanner sc = new java.util.Scanner(System.in);
	public static void Towers(int n,char a,char b,char c){
		if(n==1){
			System.out.println("移動いどう"+n+"したがえ"+a+"いた"+c);
		}
		else{
			Towers(n-1,a,c,b);
			System.out.println("移動いどう"+n+"したがえ"+a+"いた"+c);
			Towers(n-1,b,a,c);
		}
	}

	public static void main(String[] args) {
		int n = sc.nextInt();
		Towers(n,'A','B','C');
	}
}


C++ 语言实现:

#include <iostream>
using namespace std;

void Towers(int n,char a,char b,char c){
	if(n==1){
		cout<<"Move disk "<<n<<" from"<<a<<" to "<<c<<endl;
	}
	else{
		Towers(n-1,a,c,b);
		cout<<"Move disk "<<n<<" from"<<a<<" to "<<c<<endl;
		Towers(n-1,b,a,c);
	}
}
int main(int argc, char *argv[]) {
	int n;
	cin>>n;
	Towers(n,'A','B','C');
	cout<< endl;
	
	
}

Python 语言实现:

def hanoi(n, a, b, c):
	if n == 1:
		print(a, '-->', c)
	else:
		hanoi(n - 1, a, c, b)
		hanoi(1    , a, b, c)
		hanoi(n - 1, b, a, c)
# 调用
if __name__ == '__main__':
	hanoi(5, 'A', 'B', 'C')

Erlang 语言もとめかい

-module(hanoi).
-export([hanoi/1]).
hanoi(N) when N>0 ->
	do_hanoi({N, 1, 3}).

do_hanoi({0, _, _}) ->
	done;
do_hanoi({1, From, To}) ->
	io:format("From ~p, To ~p~n", [From, To]);
do_hanoi({N, From, To}) ->
	do_hanoi({N-1, From, by(From, To)}),
	do_hanoi({1, From, To}),
	do_hanoi({N-1, by(From, To), To}).

by(From, To) ->
	[Result|_] = [1, 2, 3] -- [From, To],
	Result.

Haskell 语言实现:

hanoi :: Integer -> String -> String -> String -> [(String, String)]
hanoi 0 _ _ _ = []
hanoi 1 from _ to = [(from, to)]
hanoi x from buffer to = 
    hanoi (x-1) from to buffer ++ hanoi 1 from buffer to ++ hanoi (x-1) buffer from to


任意にんいはつはじめ結構けっこう(arbitrary initial configuration)てき解法かいほう

[编辑]

ためりょうしたがえ任意にんいはつはじめ結構けっこうちゅう找尋さいけいかい(optimal solution),其演算法さんぽう一般いっぱん(be generalized)如下:

以 Scheme げん表示ひょうじ

 ; Let conf be a list of the positions of the disks in order of increasing size.
 ; Let the pegs be identified by the numbers 0, 1 and 2.
 (define (hanoi conf t)
  (let ((c (list->vector conf)))
   (define (move h f t)
    (vector-set! c h t)
    (printf "move disk ~s from peg ~s to peg ~s~n" h f t))
   (define (third-peg f t) (- 3 f t))
   (define (hanoi h t)
    (if (> h 0)
     (let ((h (sub1 h)))
      (let ((f (vector-ref c h)))
       (if (not (= f t))
        (let ((r (third-peg f t)))
         (hanoi h r)
         (move h f t)))
       (hanoi h t)))))
   (hanoi (vector-length c) t)))

ざい Javaげんちゅう

    
public class Hanoi {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(hanoiFunc(7));
	}

	public static int hanoiFunc(int i) {
		int sum = 0;

		if (i == 1) {
			sum += i;
		}

		else {
			sum = 2 * hanoiFunc(i - 1) + 1;
		}

		return sum;
	}
}

ざい Cげんちゅう

int conf[HEIGHT]; /* Element conf[d] gives the current position of disk d. */

void move(int d, int t) {
    /* move disk d to peg t */
    conf[d] = t;
}

void hanoi(int h, int t) {
    if (h > 0) {
        int f = conf[h-1];
        if (f != t) {
            int r = 3 - f - t ;
            hanoi(h-1, r);
            move(h-1, t);
        }
        hanoi(h-1, t);
    }
}

图像かい

[编辑]

以用无向图来表示ひょうじ汉诺とうざい表示ひょうじてき时候かいさら加地かじただし观和きよし晰, 虽然说理解りかいじょうゆういちてん难度。

现在规定, まい一个节点表示盘子的位置一种可能性, ごと一条边表示一种移动的方法。

ちゅう: 这里こう虑在两个ばしら间的, ぼつ有意ゆうい义的, らいかいうつり动的じょう况。

对于ただゆう一个盘子的汉诺塔,表示ひょうじ为:

对于ゆう两个盘子てき汉诺とう表示ひょうじ为:

相互そうご连接てきさん三角形さんかっけい, 组成りょう一个较大三角形的三个角。

まい一个节点的第二个字母表示更大的盘子, 且最はつ时没ゆううつり动。

对于ごといち个顶はしてきしょう三角形さんかっけい表示ひょうじ两个盘子てきいち种移动的方法ほうほう

そと围的三角形的每一个节点, 表示ひょうじざい一个柱子上盘子的所有分布可能。

对于 h+1 个盘, 就可以"复制" h 个盘时候てき三角形さんかっけい图, しかきさき拼成一个新的大三角形图, ややほろあらため动一

这个だいてき三角形图就可以用来表示 h+1 个盘时的じょう况了。

所以ゆえんとうゆう三个盘子时, 图形为:

  • a、b c 表示ひょうじさん个柱
  • 按照从小いただいてき顺序, 从左いたみぎれつてき盘子てき位置いち

さい外面がいめんてき三角形さんかっけいてき边, 表示ひょうじりょう盘子从一个柱子移动到另一个柱子最快的方式。 最大さいだいてき三角形可以沿着中线分成三个次小的三角形, 就是上面うわつらよし二级的汉诺塔组成三级的汉诺塔的逆向操作, しょう三角形相互之间的连线, 表示ひょうじ最大さいだいてき盘子てきうつり动方しき

どうざい这次三角形的也可以沿其中线分割成为三个次次三角形, いち样的, 次次つぎつぎしょう三角形相互之间的连线, 表示ひょうじだいてき盘子てきうつり动方しき。 继续, 也就表示ひょうじ一个汉诺塔的移动方式。

具有ぐゆう七个盘子的汉诺塔的图与七级的 谢尔宾斯もと三角形さんかっけい てき联系

通常つうじょう,对于具有ぐゆう n 个盘てき图, ゆう 个节てんごと个节てんゆう三条边连接着其他节点, ただしざい顶点まとてき节点ただ却只ゆうゆう两条边连接着せっちゃく其他节点。 所以ゆえん说总以将最小さいしょうてき盘子うつり动到另外两个ばしら子中こなかてきいち个, 对于多数たすうじょう况, 以在两个ばしら间移动一个盘じょりょう所有しょゆうてき盘子ざいいち个柱じょう。 边角てき节点表示ひょうじ所有しょゆうてき盘子ざい一个柱子的情况, そく以在 a, b ある c はしらじょううずたか满盘, 显然ただようさん种。 对于 个盘てき图, 以通过表示ひょうじ 给盘てき图 "复制" さん份, 组合ざいいちおこりてきよし此也就很方便ほうべん表示ひょうじりょうごと一层的汉诺塔移动方式, ごといち个次しょうてき三角形表示次小的盘子的所有可能的移动方式和放置状态, しょうてき三角形之间的连接表示了大盘子的三种可能的移动方式。 所以ゆえん图形ゆう 个节てん基本きほんゆう三个与之相连接的边, 而顶点ただゆう两个。

ざい盘子すう较多てき时候, 汉诺とうてき图像就会开始ぶんがた图比较相似そうじりょう

如果使用しようさいあさ烦的うつり动方しきそくはしじゅう复的(うつり动方しき), 需要じゅよう つぎうつり动, 每秒まいびょううつりいち需要じゅようてき时间ちょうとし

ざいこう虑重复使用しようみちてきじょう况下, じょ掉没ゆう经过てき边, 就可以表示ひょうじとうゆう三个盘子时的最长路径 。

就是ぼつゆう做无义 (あまりてき) てきはた一个盘子在两个柱子间疯狂来回移动的情况下, じょぼつゆう使用しようてきうつり动方ほう, 就可以得いたとうゆう三个盘子时的最麻烦的移动方式

顺便いちひさげ,这个さい长的じゅう复路みち以通过清じょ掉从 a いた b てきみちいた

也可以得三个盘子的汉诺塔图的 哈密顿回

该图较为清楚せいそ地表ちひょう达了:

  • 对于任意にんいてき全部ぜんぶ盘子ざい一根柱子的情况下, しょう所有しょゆう盘子うつり动到另一个柱子的最短路径只有一个。
  • 对于任意にんいてき两个盘子分布ぶんぷじょう况之间转换的时候, ただゆう一个或者两个不同的最短路径。
  • 对于任意にんいてき盘子分布ぶんぷじょう况, みやこ有一ゆういち个或しゃ两个しょう所有しょゆう盘子うつり动到任意にんい一个柱子上的最长不相交路径。
  • 对于任意にんいてき两个盘子分布ぶんぷじょう况之间转换的时候, ただゆう一个或者两个不同的最长不相交路径。
  • これはたゆう 个盘てきとうはた所有しょゆう盘子从一个柱子移动到另一个柱子的非相交路径的数量(一开始盘子都在一个柱子上)。 以得
    • N 1 = 2,

这里てき , 详细ざい A125295うえ

とう汉诺とう问题

[编辑]
  • ざいゆう 3 个柱时,しょ需步すうてき公式こうしき较简单,ただし对于 4 个柱以上いじょうじょうがた複雜ふくざつ許多きょた。Frame 及 Stewart ざい 1941ねん 分別ふんべつ提出ていしゅつりょう基本きほん上相かみやどうてきいち套演算法さんぽう[1],Bousch そくざい 2014ねん 證明しょうめいりょうFrame-Stewart演算えんざんほうざい 4 はしら就是さいけいかい[2]ただし此演算法さんぽうざい 5 はしら以上いじょうさいけいかい仍是未知みち

Frame-Stewart 演算えんざんほう本質ほんしつじょう也是递归てき簡單かんたん敘述如下:

  • れい为在ゆう 个柱时,うつり动n个圆盘到另いちはしらじょう需要じゅようてき步数ほすう,则:
对于にんなんうつり动方ほう必定ひつじょうかいさきはた 个圆盘移动到一个中间柱子上,さいしょうだい いただい 个圆盘通过剩てき 个柱うつりいた标柱じょうさいきさきしょう 在中ざいちゅう间柱じょうてき圆盘うつり动到标柱じょう。这样しょ需的操作そうさ步数ほすう
进行さい优化えきとく

流行りゅうこう文化ぶんか

[编辑]

2011ねんでんかげさるじんそう霸戰:猩凶革命かくめい》曾出現しゅつげんかわ內塔以測ためし猩猩しょうじょうてきさとししょう。其后续电かげ猩球崛起2なか也有やゆう类似てき场景。

まいり

[编辑]

參考さんこうらいげん

[编辑]
  1. ^ Stewart, B.M.; Frame, J.S. Solution to advanced problem 3819. American Mathematical Monthly. March 1941, 48 (3): 216–9. JSTOR 2304268. doi:10.2307/2304268. 
  2. ^ Bousch, T. La quatrieme tour de Hanoi. Bull. Belg. Math. Soc. Simon Stevin. 2014, 21: 895–912. 

外部がいぶ連結れんけつ

[编辑]