zoukankan      html  css  js  c++  java
  • BZOJ.1019.[SHOI2008]汉诺塔(递推)

    题目链接

    按照优先级移动,操作序列显然是唯一的。
    普通的汉诺塔是将n-1个盘子移到中间柱,再将第n个盘子移到目标柱,再将n-1个移到目标柱上的递归过程。
    对于本题移动方法还是基本一样的。考虑递推,从i-1个盘子推i个盘子。
    p[i][x]表示将x柱上的前i个盘子移走,按顺序操作最终会到哪个柱子上,f[i][x]则表示这i个盘子到p[i][x]需要移动的次数。答案即 f[n][0]。
    对于 f[i][x],先要将i-1个移到y去(设 y=p[i-1][x]),那么第i个就要移到第三个柱子z上(柱子用0,1,2标号,那么 z=3-x-y)。
    这时那i-1个盘子的状态是[i-1][y]。这也要讨论。
    若 p[i-1][y]=z,即i-1个直接放到i上,那么 f[i][x]=f[i-1][x]+1+f[i-1][y], p[i][x]=z。
    若 p[i-1][y]=x(又回到x),因为 p[i-1][x]=y,所以将i移到y上,再将i-1移到y,f[i][x]=2*f[i-1][x]+2+f[i-1][y], p[i][x]=y。
    这样转移方程就有了。
    初始化 f[1][0/1/2]=1,g[1][0/1/2]就是给定的优先级。
    因为 g[i][]会被 g[i-1][]确定,即会被优先级确定。(真的挺妙。。)

    //824kb	40ms
    #include <cstdio>
    const int N=33;
    
    int n,p[N][3];
    bool vis[5];
    long long f[N][3];
    
    int main()
    {
    	scanf("%d",&n);
    	char s[5];
    	for(int i=1; i<=6; ++i){
    		scanf("%s",s);
    		if(!vis[s[0]-'A']) p[1][s[0]-'A']=s[1]-'A',vis[s[0]-'A']=1;
    	}
    	f[1][0]=f[1][1]=f[1][2]=1;
    	for(int i=1; i<n; ++i)
    		for(int y,z,x=0; x<3; ++x)
    		{
    			y=p[i][x], z=3-x-y;
    			if(p[i][y]==z) f[i+1][x]=f[i][x]+1+f[i][y], p[i+1][x]=z;
    			else /*if(p[i][y]==x)*/ f[i+1][x]=(f[i][x]<<1)+2+f[i][y], p[i+1][x]=y;
    		}
    	
    	printf("%lld",f[n][0]);
    
    	return 0;
    }
    
  • 相关阅读:
    面试题33:把数组排成最小的数
    面试题32:从1到n整数中1出现的次数
    面试题31:连续子数组的最大和
    HTTPS 及加密信息全解析
    面试题30:最小的k个数
    linux退出vi
    linux清除当前屏幕
    java web开发环境配置
    jQuery积累
    html5离线应用详摘
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8969659.html
Copyright © 2011-2022 走看看