P4285 [SHOI2008]汉诺塔(线性dp)

题目传送门
这道题可以用 d f s dfs dfs做,也可以用 d p dp dp来完成,本题解先使用 d p dp dp来达成目标。但是真难哇,不愧是紫题呜呜呜。
d p [ i ] [ a ] dp[i][a] dp[i][a]表示把这一层上面的 i i i个盘子从 a a a柱子挪动到别的柱子需要的移动次数, p [ i ] [ a ] p[i][a] p[i][a]表示这上面的i个盘子要移动到哪个柱子 ( 1 , 2 , 3 ) (1,2,3) 123
假设现在要移动 a a a柱子上面的盘子。
那么需要更新状态
i − 1 i-1 i1个盘子移动到 p [ i − 1 ] [ a ] p[i-1][a] p[i1][a]上,然后再移动一个盘子到 1 + 2 + 3 − a − p [ i − 1 ] [ a ] 1+2+3-a-p[i-1][a] 1+2+3ap[i1][a](另外一个)
现在的步数就是 d p [ i − 1 ] [ a ] + 1 dp[i-1][a]+1 dp[i1][a]+1

b = p [ i − 1 ] [ a ] , c = 1 + 2 + 3 − a − p [ i − 1 ] [ a ] b=p[i-1][a],c=1+2+3-a-p[i-1][a] b=p[i1][a],c=1+2+3ap[i1][a]
如果 p [ i − 1 ] [ b ] = c p[i-1][b]=c p[i1][b]=c的话,那么就是把 b b b上的 i − 1 i-1 i1个盘子全部移动到c上面那么状态转移方程就是:
d p [ i ] [ a ] = d p [ i − 1 ] [ a ] + 1 + d p [ i − 1 ] [ b ] ; dp[i][a]=dp[i-1][a]+1+dp[i-1][b]; dp[i][a]=dp[i1][a]+1+dp[i1][b];
当然要更新 p [ i ] [ a ] = c p[i][a]=c p[i][a]=c(代表 a a a上面的 i i i个盘子只能挪动到 c c c柱子上面)
如果 p [ i − 1 ] [ b ] = a p[i-1][b]=a p[i1][b]=a的话,那么就是把 b b b上的 i − 1 i-1 i1个盘子全部移回来到 a a a上面,然后再把出柱子上面的第 i i i个盘子移动到 b b b上面(没得选),然后再把 a a a上面的 i − 1 i-1 i1个盘子挪动到 b b b上面,那么状态转移方程就是:
d p [ i ] [ a ] = d p [ i − 1 ] [ a ] + 1 + d p [ i − 1 ] [ b ] + 1 + d p [ i − 1 ] [ a ] ; dp[i][a]=dp[i-1][a]+1+dp[i-1][b]+1+dp[i-1][a]; dp[i][a]=dp[i1][a]+1+dp[i1][b]+1+dp[i1][a];
当然要更新 p [ i ] [ a ] = b p[i][a]=b p[i][a]=b(代表 a a a上面的 i i i个盘子只能挪动到 b b b柱子上面)

同时还要感谢 l o n g l o n g long long longlong同学的独家赞助!

#include<iostream>
using namespace std;
long long dp[210][7];
long long  p[210][7];
bool v[210];
char s[210];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=6;i++){
		scanf("%s",s);
		int a=s[0]-64,b=s[1]-64;
		if(v[a])continue;
		v[a]=1;
		p[1][a]=b;
		dp[1][a]=1;
	}
	for(int i=2;i<=n;i++){
		for(int j=1;j<=3;j++){
			int a=j,b=p[i-1][j],c=1+2+3-a-b;
			if(p[i-1][b]==c){
				dp[i][a]=dp[i-1][a]+dp[i-1][b]+1;
				p[i][a]=c;
			}
			if(p[i-1][b]==a){
				dp[i][a]=dp[i-1][a]+1+dp[i-1][b]+1+dp[i-1][a];
				p[i][a]=b;
			}
		}
	}
	cout<<dp[n][1]<<endl;
	return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值