hdu 1043 Eight(双向bfs)

题意:经典八数码问题

思路:双向bfs

ps:还有a*算法(还不会)等解法。

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

#define MAXN 362885//最多组合个数:9!=362880

int dir[4]={-3,3,-1,1};//4个方向移动:u,d,l,r
char opF[4]={'u','d','l','r'};//正向bfs操作
char opR[4]={'d','u','r','l'};//反向bfs操作
int fac[9]={1,1,2,6,24,120,720,5040,40320};//阶乘
bool visF[MAXN];//正向访问标志
bool visR[MAXN];//
string sTarg="123456789";//目标棋盘

struct node{//存储棋盘信息
    string s;//当前棋盘
    int xLoca;//x位置
}t;

struct node2{//存储操作
    int idF,idR;//正向前驱、反向前驱
    char cF,cR;//操作
}op[MAXN];

int cantor_hash(string s){//康托展开,一共n位
    int n=9;//共9位
    int i,j,temp,num;
    num=0;
    for(i=0;i<n-1;i++){//n为位数
        temp=0;
        for(j=i+1;j<n;j++){
            if(s[j]<s[i])temp++;
        }
        num+=fac[n-(i+1)]*temp;
    }
    return num;//从0开始
}

void display(int i){//输出正向操作
    if(op[i].idF==-1)return;
    display(op[i].idF);
    printf("%c",op[i].cF);
}

void dBfs(){
    queue<node>qF,qR;//正向队列,反向队列
    node tmp1,tmp2;//棋盘状态临时变量
    int id_hash,id_hash2,xLoca,i;//id 康托哈希下标值,xLoca 暂存x位置

    tmp1=t;//初始状态

    tmp2.s=sTarg;//目标状态
    tmp2.xLoca=8;//目标状态x位置

    id_hash=cantor_hash(tmp1.s);//初始状态
    visF[id_hash]=true;
    op[id_hash].idF=-1;
    qF.push(tmp1);

    id_hash=cantor_hash(tmp2.s);//目标状态
    visR[id_hash]=true;
    op[id_hash].idR=-1;
    qR.push(tmp2);

    while(!qF.empty()&&!qR.empty()){
        //正向bfs
        tmp1=qF.front();
        qF.pop();
        id_hash=cantor_hash(tmp1.s);
        if(visR[id_hash]){//反向bfs也访问过
            display(id_hash);
            id_hash2=id_hash;
            while(op[id_hash2].idR!=-1){
                printf("%c",op[id_hash2].cR);
                id_hash2=op[id_hash2].idR;
            }
            printf("
");
            return;
        }
        for(i=0;i<4;++i){
            if(i==0&&tmp1.xLoca<3)continue;
            if(i==1&&tmp1.xLoca>5)continue;
            if(i==2&&tmp1.xLoca%3==0)continue;
            if(i==3&&tmp1.xLoca%3==2)continue;
            xLoca=tmp1.xLoca+dir[i];

            tmp2=tmp1;
            swap(tmp2.s[tmp1.xLoca],tmp2.s[xLoca]);
            id_hash2=cantor_hash(tmp2.s);
            if(!visF[id_hash2]){
                visF[id_hash2]=true;
                tmp2.xLoca=xLoca;
                op[id_hash2].idF=id_hash;
                op[id_hash2].cF=opF[i];
                qF.push(tmp2);
            }
        }

        //反向bfs
        tmp1=qR.front();
        qR.pop();
        id_hash=cantor_hash(tmp1.s);
        if(visF[id_hash]){//正向bfs也访问过
            display(id_hash);
            id_hash2=id_hash;
            while(op[id_hash2].idR!=-1){
                printf("%c",op[id_hash2].cR);
                id_hash2=op[id_hash2].idR;
            }
            printf("
");
            return;
        }
        for(i=0;i<4;++i){
            if(i==0&&tmp1.xLoca<3)continue;
            if(i==1&&tmp1.xLoca>5)continue;
            if(i==2&&tmp1.xLoca%3==0)continue;
            if(i==3&&tmp1.xLoca%3==2)continue;
            xLoca=tmp1.xLoca+dir[i];

            tmp2=tmp1;
            swap(tmp2.s[tmp1.xLoca],tmp2.s[xLoca]);
            id_hash2=cantor_hash(tmp2.s);
            if(!visR[id_hash2]){
                visR[id_hash2]=true;
                tmp2.xLoca=xLoca;
                op[id_hash2].idR=id_hash;
                op[id_hash2].cR=opR[i];
                qR.push(tmp2);
            }
        }
    }
}

int main(){
    char str[32];//
    int len;//串长度
    int i,j,k;//k 第几个数码
    int ivsNum;//逆序数
    while(~scanf("%[^
]",str)){
        getchar();//吸收回车

        memset(visF,false,sizeof(visF));
        memset(visR,false,sizeof(visR));

        len=strlen(str);
        t.s="";
        k=0;//第几个数码
        for(i=0;i<len;++i){//处理字符串
            if(str[i]!=' '){
                if(str[i]=='x'){
                    t.s=t.s+'9';
                    t.xLoca=k;
                }
                else t.s=t.s+str[i];
                ++k;//
            }
        }

        ivsNum=0;//逆序数初始为0
        for(i=0;i<9;++i){
            if(t.s[i]=='9')continue;
            for(j=0;j<i;++j){
                if(t.s[j]=='9')continue;
                if(t.s[j]>t.s[i])++ivsNum;
            }
        }
        if(ivsNum&1)printf("unsolvable
");//逆序数为奇数
        else dBfs();//双向bfs
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/gongpixin/p/4825529.html