题解 P4285 [SHOI2008] 汉诺塔

发布时间 2023-10-27 21:50:46作者: reclusive2007

具体思路

\(f_{i,x}\) 表示 \(i\) 个盘子从 \(x\) 柱子出发的步数。

\(g_{i,x}\) 表示 \(i\) 个盘子从 \(x\) 柱子出发到哪个柱子。

\(y=g_{i-1,x}\)\(z=6-x-y\)

其中,\(y\) 代表将前 \(i-1\) 个盘子从 \(x\) 柱子移到的柱子,\(z\) 代表剩下的那个柱子。

分类讨论。

  • \(g_{i-1,y}=z\),表示 \(i-1\) 个盘子先从 \(x\) 移到 \(y\),第 \(i\) 个盘子从 \(x\) 移到 \(z\)\(i-1\) 个盘子再从 \(y\) 移回 \(z\)

\(f_{i,x}=f_{i-1,x}+1+f_{i-1,y},g_{i,x}=z\)

  • \(g_{i-1,y}=x\),表示 \(i-1\) 个盘子先从 \(x\) 移到 \(y\),第 \(i\) 个盘子从 \(x\) 移到 \(z\)\(i-1\) 个盘子再从 \(y\) 移回 \(x\),第 \(i\) 个盘子从 \(z\) 移到 \(y\)\(i-1\) 个盘子再从 \(x\) 移回 \(y\)

\(f_{i,x}=f_{i-1,x}+1+f_{i-1,y}+1+f_{i-1,x},g_{i,x}=y\)

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=31,M=4;
int g[N][M],vis[M];LL f[N][M];
int main(){
	int n;scanf("%d",&n);
	for(int i=1;i<=6;i++){
		char op[10];scanf("%s",op+1);
		int x=op[1]-'A'+1,y=op[2]-'A'+1;
		if(vis[x])continue;
		vis[x]=1;
		f[1][x]=1,g[1][x]=y;
	}
	for(int i=2;i<=n;i++){
		for(int x=1;x<=3;x++){
			int y=g[i-1][x],z=6-x-y;
			if(g[i-1][y]==z){
				f[i][x]=f[i-1][x]+1+f[i-1][y];
				g[i][x]=z;
			}
			if(g[i-1][y]==x){
				f[i][x]=f[i-1][x]+1+f[i-1][y]+1+f[i-1][x];
				g[i][x]=y;
			}
		}
	}
	printf("%lld\n",f[n][1]);
	return 0;
}