2020牛客寒假算法基礎集訓營3——I.牛牛的漢諾塔【記憶化】

題目傳送門


題目描述

漢諾塔是一個經典問題,相傳在古印度聖廟中,有一種被稱爲漢諾塔(Hanoi)的遊戲。該遊戲是在一塊銅板裝置上,有三根杆(編號A、B、C),在A杆自下而上、由大到小按順序放置n個金盤。遊戲的目標:把A杆上的金盤全部移到C杆上,並仍保持原有順序疊好。操作規則:每次只能移動一個盤子,並且在移動過程中三根杆上都始終保持大盤在下,小盤在上,操作過程中盤子可以置於A、B、C任一杆上。

漢諾塔以及其衍生問題往往使用遞歸來求解,也是學習和理解遞歸很好的老師。

其僞代碼如下

Function Hanoi(n,a,b,c)
    if n==1 then
        print(a+'->'+c)
    else
        Hanoi(n-1,a,c,b)
        print(a+'->'+c)
        Hanoi(n-1,b,a,c)
    end if
end Function 

牛牛很快就理解了代碼的意思並且寫出了求解漢諾塔的程序,他現在想研究漢諾塔的規律。
請你統計以下信息:A->B,A->C,B->A,B->C,C->A,C->B的次數,以及所有移動的總步數。


輸入描述:

僅一行,輸入一個正整數 n(1n60)n(1 \leq n \leq 60) 表示漢諾塔的層數。


輸出描述:

首先輸出6行
A->B:XX
A->C:XX
B->A:XX
B->C:XX
C->A:XX
C->B:XX
分別表示每種移動情況出現的次數
最後輸出一行
SUM:XX
表示所有移動情況的總和。


輸入

3


輸出

A->B:1
A->C:3
B->A:1
B->C:1
C->A:0
C->B:1
SUM:7


說明

僞代碼所示算法的移動序列如下:
A->C
A->B
C->B
A->C
B->A
B->C
A->C
統計:
A->B出現1次
A->C出現3次
B->C出現1次
B->A出現1次
C->B出現1次
總計7次


題解

  • 很熟悉的題目,遞歸 + 記憶化即可

AC-Code

#include<bits/stdc++.h>
using namespace std;
struct node {
	long long data[6];
	node() {
		memset(data, 0, sizeof(data));
	}
	//A->B      0
	//A->C      1
	//B->A      2
	//B->C      3
	//C->A      4
	//C->B      5
};

node operator + (const node& A, const node& B) {
	node C;
	for (int i = 0; i < 6; ++i)
		C.data[i] = A.data[i] + B.data[i];
	return C;
}

void moveto(int x, int y, node& temp) {
	if (x == 0 && y == 1)		++temp.data[0];
	else if (x == 0 && y == 2)	++temp.data[1];
	else if (x == 1 && y == 0)	++temp.data[2];
	else if (x == 1 && y == 2)	++temp.data[3];
	else if (x == 2 && y == 0)	++temp.data[4];
	else if (x == 2 && y == 1)	++temp.data[5];
}

node dp[3][3][3][105];
bool vis[3][3][3][105];

node hanoi(int a, int b, int c, int n) {
	if (vis[a][b][c][n])	return dp[a][b][c][n];
	if (n == 1) {
		moveto(a, c, dp[a][b][c][n]);
		vis[a][b][c][n] = true;
		return dp[a][b][c][n];
	}
	node temp;
	temp += hanoi(a, c, b, n - 1);
	moveto(a, c, temp);
	temp += hanoi(b, a, c, n - 1);
	vis[a][b][c][n] = true;
	return dp[a][b][c][n] = temp;
}

int main() {
	int n;	cin >> n;
	node ans = hanoi(0, 1, 2, n);
	printf("A->B:%lld\n", ans.data[0]);
	printf("A->C:%lld\n", ans.data[1]);
	printf("B->A:%lld\n", ans.data[2]);
	printf("B->C:%lld\n", ans.data[3]);
	printf("C->A:%lld\n", ans.data[4]);
	printf("C->B:%lld\n", ans.data[5]);
	printf("SUM:%lld\n", (1LL << n) - 1);
}
發佈了197 篇原創文章 · 獲贊 125 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章