SGU 202. The Towers of Hanoi Revisited
多柱汉诺塔问题。
引用自wiki百科
多塔汉诺塔问题
- 在有3个柱子时,所需步数的公式较简单,但对于4个以上柱子的汉诺塔尚未得到通用公式,但有一递归公式(未得到证明,但目前为止没有找到反例):
- 令为在有k个柱子时,移动n个圆盘到另一柱子上需要的步数,则:
- 对于任何移动方法,必定会先将个圆盘移动到一个中间柱子上,再将第n到第n-m个圆盘通过剩下的k-1个柱子移到目标柱子上,最后将m个在中间柱子上的圆盘移动到目标柱子上。这样所需的操作步数为。
- 进行最优化,易得: 。
1 #include <bits/stdc++.h> 2 #define rep(_i, _n) for(int _i = 1; _i <= _n; ++_i) 3 typedef long long LL; 4 typedef double DB; 5 const int inf = (INT_MAX / 3) - 10; 6 7 using namespace std; 8 const int maxn = 65 + 2; 9 int n, m; 10 int f[maxn][maxn], pos[maxn][maxn]; 11 void dfs(int a, int b) { 12 if(f[a][b] != -1) return ; 13 f[a][b] = inf; 14 if(b < 3) return ; 15 rep(r, a - 1) { 16 dfs(r, b); 17 dfs(a - r, b - 1); 18 int tmp = f[r][b] * 2 + f[a - r][b - 1]; 19 if(tmp < f[a][b]) { 20 f[a][b] = tmp; 21 pos[a][b] = r; 22 } 23 } 24 } 25 int tower[maxn][maxn], num[maxn]; 26 27 void print(int s, int t, int a, int b) { 28 if(a == 1) { 29 printf("move %d from %d to %d ", tower[s][num[s]], s, t); 30 if(num[t] != 0) printf("atop %d", tower[t][num[t]]); 31 puts(""); 32 tower[t][++num[t]] = tower[s][num[s]--]; 33 return ; 34 } 35 rep(i, m) if(i != s && i != t) { 36 if(tower[i][num[i]] > tower[s][num[s] - pos[a][b] + 1]) { 37 print(s, i, pos[a][b], b); 38 print(s, t, a - pos[a][b], b - 1); 39 print(i, t, pos[a][b], b); 40 return ; 41 } 42 } 43 } 44 45 int main() { 46 #ifndef ONLINE_JUDGE 47 freopen("data.in", "r", stdin), freopen("data.out", "w", stdout); 48 #endif 49 50 cin >> n >> m; 51 memset(f, -1, sizeof f); 52 rep(i, m) f[1][i] = 1; 53 dfs(n, m); 54 cout << f[n][m] << '\n'; 55 for(int i = n; 0 < i; --i) tower[1][++num[1]] = i; 56 rep(i, m) tower[i][0] = inf; 57 print(1, m, n, m); 58 59 return 0; 60 }
人的一切痛苦,本质上都是对自己的无能的愤怒。