UVA-10795 - A Different Task
好久没写题了,可能还是自己的意志不够坚定,懒散。。一直觉得自己脑袋不够用,却一直不努力,可悲!!
看了下纱布龙送来的刘汝佳新书,发现还是挺好的,里面有成熟详细的源码,对于我这种弱菜来说还需要借鉴别人优秀的写法和方式应该还是挺重要的
今天看了一新汉诺塔问题,在老的汉诺塔改编的版本,没看解题思路前一点思路也没有,对这方面的解题方式以前也没做吧,弱菜就是应该多训练训练!!
新汉诺塔:标准的汉诺塔上有n个大小各异的盘子。给定一个初始局面,求它到给定目标局面至少需要多少步。
旧汉诺塔:将A柱子上的n个盘子,移到B柱子上
旧汉诺塔 f(n)=f(n-1)+1+f(n-1)=(2^n)-1;f(1)=1;
首先需要把编号最大的盘子N移到目标柱子上,于是需要有这样的局面:假设N需要从A移到B,A只有N,B是空的,C上面是N-1到1,因此需要将N-1移到C,然后将N移到B,最后将N-1移到B。因此f(n)=2*f(n-1)+1;
新汉诺塔问题:首先找最大不在目标柱子上的盘子K,因为如果最大的盘子在目标柱子上它不需要移动,也不碍事。
因此问题就成了把K移动到目标柱子,把1到(k-1)移动到中转柱子,所以假设K从A移动到B,A只有K,B是空的,C上面是K-1到1,把这个局面称为参考局面。因为移动是对称的,所以从参考局面移到目标局面与目标局面移到参考局面是一样的步数。
所以问题变成答案=从初始局面移到参考局面步数+目标局面移到参考局面步数+1;
需要写一个函数f(P,i,final),表示已知个盘子的初始柱面编号数组为P,把1到i移动到final的步数,本题答案是f(start,k-1,6-start[k]-finish[k])+f(finish,k-1,6-start[k]-finish[k])+1;
计算f(P,i,final),若p[i]=final,则f(P,i,final)=f(P,i-1,final);否则需要把前i-1个盘子挪到中转盘去,将盘子i移到柱子final去,做后把前i-1个盘子从中转盘移到柱子final.。最后一步是把i-1个盘子从一个柱子移到另一个柱子,根据旧汉诺塔问题,这个步骤需要2^(i-1)-1步,加上移动盘子i那一步,一共需要2^(i-1)步。
f(P,i,final)=f(P,i-1,6-p[i]-final)+2^(i-1);
#include <iostream> #include <cstdio> #include <cstring> #define MAXN 100 #define LL long long using namespace std; int s[MAXN],t[MAXN]; LL fun(int *p,int i,int final){ if(i==0)return 0; if(p[i]==final)return fun(p,i-1,final); return fun(p,i-1,6-final-p[i])+(1LL<<(i-1)); } int main() { int n; int cas=1; while(~scanf("%d",&n)&&n){ for(int i=1;i<=n;i++) scanf("%d",&s[i]); for(int i=1;i<=n;i++) scanf("%d",&t[i]); int k=n; while(s[k]==t[k]&&k)k--; LL ans=0; if(k!=0){ int other=6-s[k]-t[k]; ans=fun(s,k-1,other)+fun(t,k-1,other)+1; } printf("Case %d: %lld\n",cas++,ans); } return 0; }