1.将某一个碟子移动到一个指定柱子上,必须首先将小于它的碟子都移动到一个临时柱子上,然后将该碟子移动到指定柱子。则将第i个碟子移动到某一柱子的开销为,
1)如果i处在目标柱子上,则开销为0,
2)如果i不在目标柱子上,则开销为H(i-1) +1 ,H为当前状态下1---(i-1)的碟子移动到 某一柱子的开销。
2. 下面讨论,某一状态下H的值:
1)将同一个柱子的n个碟子已到另一个柱子上,最少移动2^(n-1) - 1次,可由f(n) = 2*f(n-1) +1推导出;
2)将一些散乱在3个柱子上的碟子,移动到同一个柱子上。
一.将所有n-1个碟子移动到临时柱子,开销 H(n-1)
二.将n移动到指定柱子开销1
三.将临时柱子上的n-1移动到指定柱子,开销2^(n-1) - 1
由上可得,当n在指定位置时,H(n) = H(n-1),否则H(n) = H(n-1) + 2^(n-1) - 1 + 1;
假设给定共M个碟子,找出第一个不在指定位置的碟子N,将N-1个散乱的碟子移动到一个临时柱子,N移动到指定位置,开销H(n-1) +1;
接下来所有碟子处在同一个柱子上,H(n) = n处在目标位置? 0:f(n-1) + 1;
注:临时柱子一定是,目标柱子和所处柱子之外的第三个柱子
#include <cstdlib>
#include <iostream>
#include <stdio.h>
using namespace std;
const int MAX = 60 + 5;
int dsk[MAX],tag[MAX],kase = 1;
long long mov_to(int num,int peg)//把所有 <= num 的数移动到 peg 号柱子上
{
if(num == 0)return 0;
if(dsk[num] == peg)return mov_to(num - 1, peg);
return mov_to(num - 1, 6 - peg - dsk[num]) + (1LL << (num - 1));
}
long long caculate(int n)
{
long long sum = 0;
for(; n > 0 && dsk[n] == tag[n]; n--);//找出最大的 未处于目标位置的 碟子
if(n == 0)return 0;
sum += mov_to(n - 1, 6 - dsk[n] - tag[n]) + 1;
int cur = 6 - dsk[n] - tag[n];//当前 所有小于n 的碟子所在的位置
for(int i = n - 1; i > 0; i--)
{
if(tag[i] == cur)continue;
cur = 6 - cur - tag[i];
sum += (1LL << (i - 1));//所有 i-1个数 移到 临时位置的 移动次数 + 1
}
return sum;
}
int main(int argc, char *argv[])
{
int n;
while(scanf("%d",&n) != -1 && n)
{
for(int i = 1; i <= n; i++)scanf("%d",&dsk[i]);
for(int i = 1; i <= n; i++)scanf("%d",&tag[i]);
printf("Case %d: %lld\n",kase++,caculate(n));
}
//system("PAUSE");
return EXIT_SUCCESS;
}