zoukankan      html  css  js  c++  java
  • 【BZOJ】1019: [SHOI2008]汉诺塔

    http://www.lydsy.com/JudgeOnline/problem.php?id=1019

    题意:汉诺塔规则,只不过盘子n<=30,终点在B柱或C柱,每一次移动要遵守规则:1、小的不能放在大的下边。2、之前移动过的圆盘不能再次移动。3、如果有多个可移动圆盘那么按照题目所给的优先级移动。

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <string>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <set>
    #include <map>
    #include <sstream>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define rep(i, n) for(int i=0; i<(n); ++i)
    #define for1(i,a,n) for(int i=(a);i<=(n);++i)
    #define for2(i,a,n) for(int i=(a);i<(n);++i)
    #define for3(i,a,n) for(int i=(a);i>=(n);--i)
    #define for4(i,a,n) for(int i=(a);i>(n);--i)
    #define CC(i,a) memset(i,a,sizeof(i))
    #define read(a) a=getint()
    #define print(a) printf("%d", a)
    #define dbg(x) cout << (#x) << " = " << (x) << endl
    #define error(x) (!(x)?puts("error"):0)
    #define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
    inline int getint() { static int r, k; r=0,k=1; static char c; c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    
    const int N=33;
    int n;
    int m[3][3], g[3][N];
    ll f[3][N];
    int main() {
    	read(n);
    	char s[4];
    	rep(i, 6) {
    		scanf("%s", s);
    		int x=s[0]-'A', y=s[1]-'A';
    		m[x][y]=i;
    	}
    	f[0][1]=f[1][1]=f[2][1]=1;
    	g[0][1]=m[0][1]<m[0][2]?1:2;
    	g[1][1]=m[1][0]<m[1][2]?0:2;
    	g[2][1]=m[2][0]<m[2][1]?0:1;
    	for1(j, 2, n) {
    		rep(i, 3) {
    			ll &ans=f[i][j];
    			ans=f[i][j-1]+1;
    			int now=3-g[i][j-1]-i;
    			int nxt=g[i][j-1];
    			while(g[nxt][j-1]!=now || now==i) {
    				ans+=f[nxt][j-1]+1;
    				now=3-g[nxt][j-1]-now;
    				nxt=g[nxt][j-1];
    			}
    			if(g[nxt][j-1]==now) ans+=f[nxt][j-1];
    			g[i][j]=now;
    		}
    	}
    	printf("%lld
    ", f[0][n]);
    	return 0;
    }

      


    一开始想到是递推,发现了几个性质后...还是没想到怎么推QAQ,然后去翻题解...

    看到只要设两个状态就行了...于是就自己yy...还好yy出来了...

    容易发现:要想将圆盘i移动,那么在i上边的圆盘i-1~1一定移动到了另一个一样的柱上,而且,下一步一定是i移动到不同于上边两个的柱子上(优先级无用)。

    然后又容易发现:将圆盘i移动到了该移动的位置上,现在要将剩余的i-1~1的圆盘放回到i的上边,就模拟就行辣~

    所以设状态f[i,j]表示当前在i柱,要移动j到另一个柱上,g[i, j]表示移动到的另一个柱的编号。然后随便推推就行辣

    然后不知道为啥,我之前写的i移动的位置没有特判和i相等也过了QAQ......

  • 相关阅读:
    jQuery.ajax()方法笔记
    Docker安装
    Linux下Nginx+keepalived实现高可用
    Linux安装Nginx
    Redis主从、哨兵、Cluster特性
    Linux搭建redis集群
    Linux搭建redis单机
    HashMap知识总结(jdk1.8)
    如何避免form提交进行页面跳转
    异步上传文件,jquery+ajax,显示进度条
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4212388.html
Copyright © 2011-2022 走看看