題目描述
漢諾塔是一個經典問題,相傳在古印度聖廟中,有一種被稱爲漢諾塔(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的次數,以及所有移動的總步數。
輸入描述:
僅一行,輸入一個正整數 表示漢諾塔的層數。
輸出描述:
首先輸出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);
}