Chieh's Blog

Because Of Coding

UVA - 10795 A Different Task

Chieh posted @ 2015年1月28日 17:02 in UVA , 279 阅读

飞机票:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34699

题意:就是给你初始的汉诺塔大小升序,和目标的汉诺塔大小升序,求最小的移动步数;

分析:刚开始没有想法,后来想到了万法归宗,就是已知初始状态变回原始状态也是可行的就是说假如A,B,C三个分别有编号1,2,3的盘子,我们可以变回A,B,C只有A上有3个盘子的状态好复杂,所以我是用了反推的方法,先设A,B,C有3个盘子,然后推出A,B,C分别有1个盘子的步数为几步。。所以加个判断,加入当前盘子是A,当前要移动的最大盘是k,要移动到B,则上面的k-1个盘都要移动到C才行,就是2^(k-1)步,这里不用减1,因为k要移一步。这样先把初始的都先归到一个盘子一共要几步,然后根据当前的盘要移动到哪进行计算步数就ok了,

解释下吧:

对于第一个样例,我们可以把第3个盘提出来,则1,2个盘回到C上去,这样一共要3步+第三个盘要1步,就是4步,然后1,2都在C上,当要把2移到B上时,我们得把2上面的移到A上,则要1步+第二个盘要1步,就是2步,最后再加上第一个盘移一次就是答案了,7;

啪啪啪~就可以AC了

/*
Author:Chieh
Grow up happy
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <stack>
#define LL long long
using namespace std;
const int maxn=67;
struct he
{
    int s,e;
} JLJ[maxn];
int n;
void init()
{
    for(int i=1; i<=n; i++)scanf("%d",&JLJ[i].s);
    for(int i=1; i<=n; i++)scanf("%d",&JLJ[i].e);
}
void play()
{
    int st=-1;
    for(int i=n; i>=1; i--)
    {
        if(JLJ[i].s!=JLJ[i].e)
        {
            st=i;
            break;
        }
    }
    if(st==-1)
    {
        printf("0\n");
        return;
    }
    LL sum=0;
    int now=6-JLJ[st].s-JLJ[st].e;
    for(int i=st-1; i>=1; i--)
    {
        if(JLJ[i].s==now)
            continue;
        else
        {

            sum+=((1LL)<<(i-1));
            now=6-JLJ[i].s-now;
        }
    }
    sum++;
    now=6-JLJ[st].s-JLJ[st].e;
    for(int i=st-1; i>=1; i--)
    {
        if(JLJ[i].e==now)continue;
        else
        {
            sum+=((1LL)<<(i-1));
            now=6-JLJ[i].e-now;
        }
    }
    printf("%lld\n",sum);
}
int main()
{
    int Ca=1;
    while(scanf("%d",&n)!=EOF)
    {   if(n==0)break;
        init();
        printf("Case %d: ",Ca++);
        play();
    }
    return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter