在任何操作执行之前,我们以任意的次序为六种操作(AB、AC、BA、BC、CA 和 CB)赋予不同的优先级,然后,我们总是选择符合以下两个条件的操作来移动盘子,直到所有的盘子都从柱子 A 移动到另一根柱子:
- 这种操作是所有合法操作中优先级最高的;
- 这种操作所要移动的盘子不是上一次操作所移动的那个盘子。
可以证明,上述策略一定能完成汉诺塔游戏。 现在你的任务就是假设给定了每种操作的优先级,计算按照上述策略操作汉诺塔移动所需要的步骤数。
链接
题解
设 表示只考虑柱子 上的最上面的 个盘子(不考虑下面更大的盘子和其它柱子上的盘子),将这些盘子移动到 上的步数。
根据汉诺塔的规则,我们需要先移动前 个盘子,需要 次操作,这些盘子被移动到 上。设 ,则另一个柱子 。我们需要把第 个盘子移动到 上。
继续考虑移动到 上的 个盘子,这些盘子需要移动到 上,如果 ,则直接将它们移到 上,此时 个盘子均已移动到 上,所以 ,。
如果 则需要将 个盘子移回 柱子,然后将最大的盘子移到 上,再将前 个盘子移到 上(因为 )。所以 ,
代码
#include <cstdio>
const int MAXN = 30;
int main() {
int n;
scanf("%d", &n);
static int g[MAXN + 1][3];
g[1][0] = g[1][1] = g[1][2] = -1;
for (int i = 0; i < 6; i++) {
char s[3];
scanf("%s", s);
int a = s[0] - 'A', b = s[1] - 'A';
if (g[1][a] == -1) g[1][a] = b;
}
static long long f[MAXN + 1][3];
f[1][0] = f[1][1] = f[1][2] = 1;
for (int j = 2; j <= n; j++) {
for (int i = 0; i < 3; i++) {
const int a = g[j - 1][i], b = 3 - a - i;
if (g[j - 1][a] == b) {
f[j][i] = f[j - 1][i] + 1 + f[j - 1][a];
g[j][i] = b;
} else {
f[j][i] = f[j - 1][i] + 1 + f[j - 1][a] + 1 + f[j - 1][i];
g[j][i] = a;
}
}
}
printf("%lld\n", f[n][0]);
return 0;
}