题目传送门
这道题可以用
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)
(1,2,3)
假设现在要移动
a
a
a柱子上面的盘子。
那么需要更新状态
将
i
−
1
i-1
i−1个盘子移动到
p
[
i
−
1
]
[
a
]
p[i-1][a]
p[i−1][a]上,然后再移动一个盘子到
1
+
2
+
3
−
a
−
p
[
i
−
1
]
[
a
]
1+2+3-a-p[i-1][a]
1+2+3−a−p[i−1][a](另外一个)
现在的步数就是
d
p
[
i
−
1
]
[
a
]
+
1
dp[i-1][a]+1
dp[i−1][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[i−1][a],c=1+2+3−a−p[i−1][a]
如果
p
[
i
−
1
]
[
b
]
=
c
p[i-1][b]=c
p[i−1][b]=c的话,那么就是把
b
b
b上的
i
−
1
i-1
i−1个盘子全部移动到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[i−1][a]+1+dp[i−1][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[i−1][b]=a的话,那么就是把
b
b
b上的
i
−
1
i-1
i−1个盘子全部移回来到
a
a
a上面,然后再把出柱子上面的第
i
i
i个盘子移动到
b
b
b上面(没得选),然后再把
a
a
a上面的
i
−
1
i-1
i−1个盘子挪动到
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[i−1][a]+1+dp[i−1][b]+1+dp[i−1][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;
}