Test Message

a268: 河內塔問題

內容

相信大家都知道著名的河內塔問題。簡單來說,就是有三根柱子,柱子上可以套多個圓盤,圓盤大小都不同,但是每次移動一個圓盤的時候都不能有較大的圓盤在較小的圓盤上。一般來說一開始的初始狀態是所有圓盤都在同一根柱子上,目標是在不違反規則的條件下,至少移動幾次圓盤可使所有圓盤移動到另外一根柱子上。

我們的問題比較複雜一點,給定圓盤的初始狀態以及目標狀態,問至少要移動幾次能從初始狀態到目標狀態。


輸入

每個測資檔包含多筆測資。每筆測資包含三行,第一行是一個正整數 N (1<=N<=10000),代表圓盤的個數。第二行及第三行分別代表圓盤的初始與目標狀態。每行有 N 個正整數,第 i 個數 Si 代表第 i 小的圓盤是套在 Si 上,其中 Si 只可能是 1 或 2 或 3。當 N=0 時代表輸入結束。

4
1 1 1 1
1 2 2 1
3
1 1 1
2 2 2
3
1 2 3
3 2 1
4
1 1 1 1
1 1 1 1
31
3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
0

輸出

對每筆測資輸出一行,代表從初始狀態到目標狀態至少要移動幾次圓盤。由於答案可能很大,請輸出 mod 1,000,000,007 的結果。

6
7
3
0
147483633


解題思路

b592 的進化版,一樣的解題邏輯就不再寫一遍了。

這題雖然測資比較變態,但只要演算法沒錯、該建的表有建、不要做多餘的操作,時間壓力並不大。


完整程式碼

AC (21ms, 148KB)
#include <stdio.h>
#define MAX 10001
#define MOD 1000000007

int steps, step[MAX] = { 1 }, n, base;
char now[MAX], to[MAX], end[MAX], curr;

int main()
{
for (int i = 1; i < MAX; i++)
step[i] = (step[i - 1] << 1) % MOD;
while (scanf(" %d", &n) == 1 && n)
{
steps = 0, base = 1;
for (int i = 1; i <= n; i++)
scanf(" %d", &now[i]);
for (int i = 1; i <= n; i++)
scanf(" %d", &end[i]);
while (now[n] == end[n] && n)
n--;
if (n)
{
while (now[base + 1] == now[1] && base < n - 1)
base++;
to[n] = end[n];
for (int i = n; i > 1; i--)
to[i - 1] = now[i] == to[i] ? to[i] : 6 - now[i] - to[i];
curr = now[base];
for (int i = base + 1; i <= n; i++)
{
if (now[i] == to[i]) continue;
if (now[i] + to[i] + curr == 6)
steps++;
else
steps = (steps + step[base]) % MOD, base = i - 1, curr = 6 - now[i] - to[i];
}
curr = to[n - 1];
for (int i = base; i; i--)
{
if (curr == end[i]) continue;
curr = 6 - curr - end[i];
steps = (steps + step[i - 1]) % MOD;
}
printf("%d\n", steps);
}
else
{
puts("0");
}
}
return 0;
}