汉诺塔问题
解决思路(分治)
以三根柱子,n个圆盘为例;
将一根柱子上的所有圆盘分成上n - 1堆和最下面一个,先设法将n - 1个移动到第二根柱子上(中转站),再将最大的一个盘子移动到目标柱子上;
随后再将第一根柱子作为中转站,将第二根柱子上的n - 1个圆盘设法移动到目标柱子上
递归求解方式
class Solution {
int ans = 0;
void dfs(int n, List<Integer> A, List<Integer> B, List<Integer> C) {
ans ++ ;
if (n == 1) {
C.add(A.remove(A.size() - 1));
return ;
}
dfs(n - 1, A, C, B);
C.add(A.remove(A.size() - 1));
dfs(n - 1, B, A, C);
}
public int hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
dfs(A.size(), A, B, C);
// System.out.println(ans);
return ans;
}
}
递推求解方式
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f;
const int N = 15;
int d[N], f[N];
int main() {
d[1] = 1;
for (int i = 2; i <= 12; i ++ ) {
// 1: 最长的一根移动到第三根柱子上
// d[i - 1] * 2: 其余n - 1部分的盘子,先移动到中转柱子上,再移动到第三根柱子上,两次移动所以*2
d[i] = 1 + d[i - 1] * 2;
}
memset(f, INF, sizeof f);
f[0] = 0;
for (int i = 1; i <= 12; i ++ ) {
for (int j = 0; j < i; j ++ ) {
// 分成j和i - j两部分
// 先将j个盘子移动到2或3其中作为中转盘子
// 剩余的i - j个盘子和剩余的3个柱子构成d[]中我们求解的结果得出
f[i] = min(f[i], f[j] * 2 + d[i - j]);
}
}
for (int i = 1; i <= 12; i ++ ) cout << f[i] << endl;
return 0;
}