洛谷 P1242 新汉诺塔 dfs递归
优先保证编号较大的到达目标位置,把其他编号较小的盘子都先移到中间柱子上。
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 50
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
//p1记录原始位置,p2记录目标位置
int n,p1[MAX],p2[MAX],ans=0;
void dfs(int id,int pos1,int pos2){
if(pos1==pos2){//说明不需要转移
return;
}
for(int i=id-1;i>=1;i--){//把所有比id小的圆盘移到中转柱上
dfs(i,p1[i],6-pos1-pos2);
}
p1[id]=pos2;
printf("move %d from %c to %c\n",id,'A'+pos1-1,'A'+pos2-1);
ans++;
}
int main(){
scanf("%d",&n);
int k,x;
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p1[x]=1;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p1[x]=2;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p1[x]=3;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p2[x]=1;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p2[x]=2;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p2[x]=3;}
for(int i=n;i>=1;i--){
dfs(i,p1[i],p2[i]);//将第i号盘子从原始柱子移动到目标柱子上
}
printf("%d",ans);
return 0;
}
对于n号盘子,有两种移动方案:
(1)先移动到中间柱子上,再移动到目标柱子上
(2)直接移动到目标柱子上
我们取两种方案的最小值即可。
#include
#include
#include
#include
#include
#include
#include
#include
#define MAX 50
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
struct node{
int id;
int s;
int f;
}t_mov[1000005],mov[1000005];
//p1记录原始位置,p2记录目标位置
int n,p1[MAX],p2[MAX],t1[MAX],t2[MAX],minl=INF,ans=0;
void dfs(int id,int pos1,int pos2){
if(pos1==pos2){//说明不需要转移
return;
}
for(int i=id-1;i>=1;i--){//把所有比id小的圆盘移到中转柱上
dfs(i,t1[i],6-pos1-pos2);
}
t1[id]=pos2;
ans++;
t_mov[ans].id=id,t_mov[ans].s=pos1,t_mov[ans].f=pos2;
}
int main(){
scanf("%d",&n);
int k,x;
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p1[x]=1;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p1[x]=2;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p1[x]=3;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p2[x]=1;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p2[x]=2;}
scanf("%d",&k);for(int i=0;i<k;i++){scanf("%d",&x);p2[x]=3;}
for(int i=1;i<=2;i++){//两种方案,第1种为直接移动,第2种为间接移动
ans=0;
for(int j=1;j<=n;j++){//t1,t2为中间量
t1[j]=p1[j];
t2[j]=p2[j];
}
if(i==1) dfs(n,t1[n],t2[n]);//直接移动
else dfs(n,t1[n],6-t1[n]-t2[n]);
for(int j=n-1;j>=1;j--){
dfs(j,t1[j],t2[j]);
}
for(int j=n;j>=1;j--){
dfs(j,t1[j],t2[j]);
}
if(i==2){//若是间接移动,我们需要重新把n号盘子放回目标柱子上
for(int j=n;j>=1;j--){
dfs(j,t1[j],t2[j]);
}
}
if(ans<minl){
for(int j=1;j<=ans;j++){
mov[j]=t_mov[j];
}
minl=ans;
}
}
for(int i=1;i<=minl;i++){
printf("move %d from %c to %c\n",mov[i].id,'A'+mov[i].s-1,'A'+mov[i].f-1);
}
printf("%d",minl);
return 0;
}