uva10795 - A Different Task(新汉诺塔问题)

这个题不同的是开始状态不规则,目标状态也不规则

我们这里有个折中的方法,就是从开始和目标两个状态同时向一个参考状态移动。

我们分析这个问题,会发现我们必须先把最大的圆盘放到目标位置,所以目前位置s和目标位置p上都不能存在其他比当前圆盘小的圆盘,然后把最大的圆盘从s移动到p上,

所以ans等于把其他的圆盘从s移动到中转位置的步骤数step1加上把其他的圆盘从p移动到中转位置的步骤数step2再加上1

所以ans = step1+step2+1;

其他的移动方式和经典的汉诺塔差不多了,

不过我们发现总共3个位置,

要想把其他的圆盘移动到中转位置上,s和p位置上除了当前圆盘外都是空的,那么中转位置上肯定是有序的,从上倒下圆盘半径依次减小。

所以我们把其他的小圆盘再从中转位置移动到目的位置,那么步骤数就和经典汉诺塔一样了。

即有n个盘子需要移动的话,就需要2^(n-1)-1次移动。

在加上中间把当前圆盘移动一次。

所以把小圆盘移动都中转圆盘后只需2^(n-1)次移动就能实现把所有比当前圆盘小的圆盘移动到墓地位置了

代码如下;

#include <cstdio>
#define M 70
int start[M], targe[M];
long long f(int *p, int k, int fina)
{
    if(k==0) return 0;
    if(p[k]==fina) return f(p,k-1,fina);
    return f(p,k-1,6-fina-p[k])+(1LL<<(k-1));
}
int main ()
{
    long long ans;
    int n, cas = 0;
    while(scanf("%d",&n), n)
    {
        for(int i = 1; i <= n; i++) scanf("%d",&start[i]);
        for(int i = 1; i <= n; i++) scanf("%d",&targe[i]);
        int c = n;
        for(;c>=1&&start[c]==targe[c];c--);
        printf("Case %d: ",++cas);
        if(c==0) {printf("0\n"); continue;}
        int other = 6 - start[c] - targe[c];
        ans = f(start,c-1,other)+f(targe,c-1,other)+1;
        printf("%lld\n",ans);
    }
    return 0;
}




你可能感兴趣的:(uva10795 - A Different Task(新汉诺塔问题))