• hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】


    <题目链接>

    题目大意:
    给出一个3×3的矩阵(包含1~8数字和一个字母x),经过一些移动格子上的数后得到连续的1~8,最后一格是x,要求最小移动步数。

    解题分析:
    本题用BFS来寻找路径,为了降低复杂度,用BFS从最终的目标状态开始处理,将所有搜索到状态以及对应的路径打表记录,然后对于输入的矩阵,直接查表输出答案 即可,本题还有一个难点,就是如何判断记录已经搜索过的状态,如果使用map+string(矩阵看成一维)会超时,所以我们这里用康拓展开式来记录状态。这道题比较玄学的地方在于如果更换dir 中四个方向的顺序,可能会WA,而在题目中没有对输出的字符串做任何限制,不知道这是为什么。

    #include<cstdio>  
    #include<iostream>  
    #include<queue>  
    using namespace std;  
    typedef struct nn  
    {  
        char way;     //记录操作
        int fath;     //记录父节点,用于记录路径  
    }node1;  
    
    typedef struct nod  
    {  
        int aa[10];  
        int n;      //n为9在aa中的位置 
        int son;    //记录aa的康拓展开式
    }node2;  
    
    int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}},fac[10];  
    node1 Node[370000];//节点  
    
    void set_fac()//计算0到8的阶层  
    {  
        fac[0]=1;  
        for(int i=1;i<=8;i++)  
        fac[i]=fac[i-1]*i;
    }  
    
    int cantor(int aa[])//康托展开,掌握康拓展开的方法
    {  
        int ans=0; 
        for(int i=0;i<9;i++)  
        {  
            int k=0;  
            for(int j=i+1;j<9;j++)  
            if(aa[i]>aa[j])  
            k++;  
            ans+=k*fac[8-i];  //i点以后比aa[i]小的数的个数*((n-i)-1)! 之和 
        }  
        return ans;  
    }  
    
    void bfs(int a[]) 
    {  
        queue<node2>Q;  
        node2 now,next;  
    
        for(int i=0;i<9;i++) now.aa[i]=a[i];  
        now.n=8;now.son=0;  
        Node[now.son].fath=0;        //把最终父节点记为0,也就是本身  
        Q.push(now);  
        while(!Q.empty())  
        {  
            now=Q.front(); Q.pop();  
            for(int k=0;k<4;k++)  
            {  
                next=now;  
                int tx=now.n/3+dir[k][0];
                int ty=now.n%3+dir[k][1];   
                if(ty>=0&&tx>=0&&ty<3&&tx<3)  
                {  
                    next.n=tx*3+ty;      //得到移动后x的位置
                    int tem=next.aa[next.n];    //得到移动后该位置的原数字
                    next.aa[next.n]=next.aa[now.n];
                    next.aa[now.n]=tem;         //将两个位置上的数字交换
                    next.son=cantor(next.aa); 
    
                    if(Node[next.son].fath==-1)     //为-1时表示这个点没有访问过,那么放入队列  
                    {  
                        Node[next.son].fath=now.son;   //当前节点的父节点就是上一个节点  
                        if(k==0)Node[next.son].way='l';//一定要注意了,k=0是向右走,但我们是从终止状态往回搜,所以直接记录相反的方向  
                        if(k==1)Node[next.son].way='r';  
                        if(k==2)Node[next.son].way='u';  
                        if(k==3)Node[next.son].way='d';  
                        Q.push(next);  
                    }  
                }  
            }  
        }  
    }  
        
    int main()  
    {  
        int i,j,s,ss[10],a[10];  
         
        for(i=0;i<9;i++)//目标状态  
            a[i]=i+1;                //建立目标一维矩阵,把x看成9  
    
        for(i=0;i<370000;i++)  
        Node[i].fath=-1;  
        set_fac();     //计算阶层  
            bfs(a);    //将从最终状态能够延伸出去的所有状态以及对应路径提前打表记录 
    
        char str[50]; 
        while(gets(str))  
        {  
            for(i=0,j=0;str[i]!='';i++)//把字符串变成数子  
            {  
                 if(str[i]=='x')  
                ss[j++]=9;  //把x变为数子9  
                else if(str[i]>='0'&&str[i]<='8')  
                ss[j++]=str[i]-'0';  
            }  
            s=cantor(ss);    //算出初态康托值  
           if(Node[s].fath==-1) {printf("unsolvable
    ");continue;}   //不能变成目标,因为当从起点开始搜索的时候,fath表示搜索到某
           //点时,上一个点的状态,所以,如果s.fath==-1时,表示这个矩阵根本就延伸不出去,不可能达到目标状态
             
            while(s!=0)  
            {  
                printf("%c",Node[s].way);  
                s=Node[s].fath;  
            }  
            printf("
    ");  
        }  
    }

    2018-09-06

  • 相关阅读:
    Maven介绍
    自考:计算机网络原理 2018版 李全龙 课后习题答案
    jmeter分布式部署遇到的坑
    mysql循环 insert插入多条数据
    认识Nacos.
    mysql中where子句中使用别名查询出现问题
    python之bytes和string相互转换
    什么叫线圈?什么寄存器?什么叫保持寄存器?
    Modbus-RTU详解(转载)
    python进制之间的转换函数
  • 原文地址:https://www.cnblogs.com/00isok/p/9595726.html
Copyright © 2020-2023  润新知