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

<题目链接>

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

解题分析:
本题用BFS来寻找路径,为了降低复杂度,用BFS从最终的目标状态开始处理,将所有搜索到状态以及对应的路径打表记录,然后对于输入的矩阵,直接查表输出答案 即可,本题还有一个难点,就是如何判断记录已经搜索过的状态,如果使用map+string(矩阵看成一维)会超时,所以我们这里用康拓展开式来记录状态。

#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]={{1,0},{-1,0},{0,1},{0,-1}},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][1];
            int ty=now.n%3+dir[k][0];
            if(ty>=0&&tx>=0&&ty<3&&tx<3)
            {
                next.n=tx*3+ty;
                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]!=‘\0‘;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\n");continue;}   //不能变成目标,因为当从起点开始搜索的时候,fath表示搜索到某
       //点时,上一个点的状态,所以,如果s.fath==-1时,表示这个矩阵根本就延伸不出去,不可能达到目标状态

        while(s!=0)
        {
            printf("%c",Node[s].way);
            s=Node[s].fath;
        }
        printf("\n");
    }
}

2018-09-06

原文地址:https://www.cnblogs.com/00isok/p/9595726.html

时间: 2024-08-15 16:04:18

hdu 1043 Eight (八数码问题)【BFS】+【康拓展开】的相关文章

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

Hdu 1043 Eight (八数码问题)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1043 题目描述: 3*3的格子,填有1到8,8个数字,还有一个x,x可以上下左右移动,问最终能否移动到12345678x的状态? hint:每一个3*3的格子从上到右,从左到右,一行一行读. 解题思路: 比较简单的八数码问题,大一暑假老师讲过,一直手懒脑懒并没有亲自尝试过.因为是多实例,先从12345678x的状态bfs出来所有可以到达的状态,并且记录下来路径.八数码最重要的就是保存状态,如果这个

【HDU - 1043】Eight(反向bfs+康托展开)

Eight Descriptions: 简单介绍一下八数码问题:在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图: 1 2 3 4 5 6 7 8   在上图中,由于右下角位置是空的,你可以移动数字,比如可以将数字6下移一位: 1 2 3   1 2 3 4 5 6 → 4 5   7 8     7 8 6 或者将数字8右移一位: 1 2 3   1 2 3 4 5 6 → 4 5 6 7 8     7   8 1~8按顺序排列的情况称为"初始状态"(如最上方图)

UVA 10085(bfs+康拓展开)八数码问题

Description Problem A The Most Distant State Input: standard input Output: standard output The 8-puzzle is a square tray in which eight square tiles are placed. The remaining ninth square is uncovered. Each tile has a number on it. A tile that is adj

cdoj 1380 Xiper的奇妙历险(2) [八数码问题 bfs + 预处理]

快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚至还用过A*来优化时间.不过这道题懒得写了,就一个普普通通的bfs,再加上一个stl 的map就水过了. 首先题目要求有多达10000组数据,依次搜索肯定是不行的,我试过用A*来写,第2组数据就会T掉,所以我们考虑用一个预处理.从末尾状态搜索所有可行的状态,并用一个map来存储答案.然后就很好写了.

九宫重拍(bfs + 康拓展开)

问题描述 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成第二个图所示的局面. 我们把第一个图的局面记为:12345678. 把第二个图的局面记为:123.46758 显然是按从上到下,从左到右的顺序记录数字,空格记为句点. 本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达.如果无论多少步都无法到达,则输出-1. 输入格式 输入第一行包含九宫的初态,第二行包含九宫的终态. 输出格式 输出最

845. 八数码(bfs+map)

在一个3×3的网格中,1~8这8个数字和一个“X”恰好不重不漏地分布在这3×3的网格中. 例如: 1 2 3 X 4 6 7 5 8 在游戏过程中,可以把“X”与其上.下.左.右四个方向之一的数字交换(如果存在). 我们的目的是通过交换,使得网格变为如下排列(称为正确排列): 1 2 3 4 5 6 7 8 X 例如,示例中图形就可以通过让“X”先后与右.下.右三个方向的数字交换成功得到正确排列. 交换过程如下: 1 2 3 1 2 3 1 2 3 1 2 3 X 4 6 4 X 6 4 5 6

八数码问题--bfs

1 #include<iostream> 2 #include<cstring> 3 #define max 1000000 4 using namespace std; 5 const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}}; 6 string origion; 7 string goal; 8 string state[max]; 9 int vis[370000]; 10 11 bool encode(string str){ //

hdoj1043 Eight(逆向BFS+打表+康拓展开)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1043 思路: 由于自己对康拓展开用的太少,看到这个题没想到康拓展开,最开始打算直接转换为数字,但太占内存了,又想到可以将状态存进set,后来查了一下发现原来是考察康拓展开.另外就是需要打表预处理,这样快很多.BFS部分就是已知终点,从终点逆向搜索,并存每个状态的上一个状态以及操作,以便输出. 坑点:输入是多组输入,POJ那道题才是一组输入,卡在这一上午T_T. 有一组输入为12345678x,需要特