UVA - 10795 A Different Task
Chieh
posted @ 2015年1月28日 17:02
in UVA
, 294 阅读
飞机票: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; }