洛谷 P1242 新汉诺塔 dfs递归

寵の児 提交于 2020-02-02 08:13:43

洛谷 P1242 新汉诺塔 dfs递归

90分代码:

优先保证编号较大的到达目标位置,把其他编号较小的盘子都先移到中间柱子上。

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<cstring>
#include<vector>
#include<map>
#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;
}


模拟退火也可(概率论?),但我不太会


AC思路:

对于n号盘子,有两种移动方案:
(1)先移动到中间柱子上,再移动到目标柱子上
(2)直接移动到目标柱子上
我们取两种方案的最小值即可。

AC代码:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cmath>
#include<queue>
#include<cstring>
#include<vector>
#include<map>
#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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!