HDU 1043 八数码(A*搜索)

在学习八数码A*搜索问题的时候需要知道以下几个点:

Hash:利用康托展开进行hash

康托展开主要就是根据一个序列求这个序列是第几大的序列。

A*搜索:这里的启发函数就用两点之间的曼哈顿距离进行计算就可以。

减枝:在八数码里,任意交换一个空行和一个位置的数字,这个八数码的逆序数是不变的,这样就可以根据目前状态判断是否可达终点状态了。

第一次做这个题用的map进行哈希,结果果断超时,之后又写了LRJ书上的hash方法也超时了,最后只能用康托展开了

详细请参考:【八数码的八重境界】 http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html

/*
    康托展开
    A* 算法
    八数码逆序数性质
*/
#include<cmath>
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 370015;
//322560
struct State{
    int mat[3][3];
    int h,g,cvalue;
    int posx,posy;
    friend bool operator < (State p,State q){
        if(p.h != q.h)
            return p.h > q.h;
        else
            return p.g > q.g;
    }
}start;
int  vis[maxn],fa[maxn],cnt;
//-------------------init----------------------------------
void init(){
    memset(vis,-1,sizeof(vis));
    memset(fa,-1,sizeof(fa));
    cnt = 0;
}
bool isok(State &state){
    int temp[9];
    for(int i = 0,k = 0; i < 3; i ++)
        for(int j = 0; j < 3; j++,k++)
            temp[k] = state.mat[i][j];
    int ret = 0;
    for(int i = 0; i < 9; i++)
        for(int j = 0; j < i; j++){
            if(temp[i] && temp[j] && temp[j] > temp[i])
                ret ++;
        }
    return (ret & 1) ? 0 : 1;
}
//---------------------------------------------------------
const int Hash[] = {1,1,2,6,24,120,720,5040,40320};
int Cantor(State &stemp){
    int temp[9];
    for(int i = 0,k = 0; i < 3; i++)
        for(int j = 0; j < 3; j++, k++)
            temp[k] = stemp.mat[i][j];
    int ret = 0;
    for(int i = 0; i < 9; i++){
        int val = 0;
        for(int j = 0; j < i; j++)
            if(temp[j] > temp[i]) val ++;
        ret += Hash[i] * val;
    }
    return ret;
}
//----------------------------------------------------------
int get_h(State &temp){
    int ret = 0;
    for(int i = 0; i < 3; i++)
        for(int j = 0; j < 3; j++){
            ret +=
            abs(i - (temp.mat[i][j] - 1)/3) + abs(j - (temp.mat[i][j] - 1) % 3);
        }
    return ret;
}
//----------------------------------------------------------
//ulldrdrulldrruldlurrd
const char cdir[] = "dlru";
const int dir[4][2] = {{1,0},{0,-1},{0,1},{-1,0}}; //d l r u
void dfs_print(int u){
    if(vis[u] < 0)
        return;
    dfs_print(fa[u]);
    printf("%c",cdir[vis[u]]);
}
bool bfs(){
    priority_queue<State>q;
    start.cvalue = Cantor(start);
    start.h = get_h(start);
    start.g = 0;
    q.push(start);
    vis[start.cvalue] = - 2;
    State temp;
    while(!q.empty()){
        State now = q.top(); q.pop();
        if(now.cvalue == 322560){
            dfs_print(now.cvalue);
            puts("");
            return true;
        }
        for(int i = 0; i < 4; i++){
            temp = now;
            int x = now.posx + dir[i][0];
            int y = now.posy + dir[i][1];
            temp.posx = x;
            temp.posy = y;
            if(x >= 0 && x < 3 && y >= 0 && y < 3){
                swap(temp.mat[x][y],temp.mat[now.posx][now.posy]);
                int cvalue = Cantor(temp);
                if(vis[cvalue] == -1 && isok(temp)){
                    vis[cvalue] = i;
                    fa[cvalue] = now.cvalue;
                    temp.h = get_h(temp);
                    temp.g = now.g + 1;
                    temp.cvalue = cvalue;
                    q.push(temp);
                    if(temp.cvalue == 322560){
                        dfs_print(cvalue);
                        puts("");
                        return true;
                    }
                    cnt ++;
                }
            }
        }
    }
    return false;
}
int main(){
    char _in[10][2];
    while(scanf("%s",_in[0]) != EOF){
        init();
        for(int i = 1; i < 9; i++)
            scanf("%s",_in[i]);
        for(int k = 0,i = 0; i < 3; i++)
            for(int j = 0; j < 3; j++,k ++){
                if(_in[k][0] == 'x'){
                    _in[k][0] = '0';
                    start.posx = i;
                    start.posy = j;
                }
                start.mat[i][j] = _in[k][0] - '0';
            }
        if(!bfs())
            printf("unsolvable\n");
    }
    return 0;
}
/*
1
2
6
24
120
720
5040
40320
*/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-02 02:48:22

HDU 1043 八数码(A*搜索)的相关文章

HDU 1043 八数码(八境界)

8境界:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 境界一. 暴力广搜+STL (HDU 内存超限,POJ 时间超限) map存路径,set判重,string存状态,毫无疑问,炸了. #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<vector> #inclu

HDU 4021 八数码问题

24 Puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)Total Submission(s): 1466    Accepted Submission(s): 433 Problem Description Daniel likes to play a special board game, called 24 puzzle. 24 puzzle is such a

(中等) HDU 1043 Eight,经典搜索问题。

Problem Description The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've seen it. It is constructed with 15 sliding tiles, each with a number from 1 to 15 on it, and all packed into a 4 by 4 frame with one

搜索进阶1、八数码(HDU1043)

http://acm.hdu.edu.cn/showproblem.php?pid=1043 八数码八境界: https://www.cnblogs.com/zufezzt/p/5659276.html 借用了MAP哈希,发现只能过hdu(249ms),poj一直TLE. 还是先上个代码吧,以后再改用康拓展开来哈希.. 1 #include<stdio.h> 2 #include<algorithm> 3 #include<string.h> 4 #include<

关于八数码问题中的状态判重的三种解决方法(编码、hash、&lt;set&gt;)

八数码问题搜索有很多高效方法:如A*算法.双向广搜等 但在搜索过程中都会遇到同一个问题,那就是判重操作(如果重复就剪枝),如何高效的判重是8数码问题中效率的关键 下面关于几种判重方法进行比较:编码.hash.set 看到问题初学者最先想到的应该就是用一个vis数组标志一下即可.但是该申请多大的数组呢?一个9维数组(9^9=387420489太大了吧)?如果内存允许这是最高效的办法:O(1) 所以我们现在面临的问题是如何在O(1)的时间复杂度不变的情况下把空间压缩下来: 方法一:编码.解码,我们可

HDU 1043 POJ 1077 八数码问题

以下内容转载自:http://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html 八数码的八境界 研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor ove

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+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(八数码)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo