Hdu1043 Eight 【A*搜索】八数码问题

http://acm.hdu.edu.cn/showproblem.php?pid=1043

经典八数码问题的启发式搜索

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <queue>
using namespace std;
template <class T> void checkmin(T &t,T x) {if(x < t) t = x;}
template <class T> void checkmax(T &t,T x) {if(x > t) t = x;}
template <class T> void _checkmin(T &t,T x) {if(t==-1) t = x; if(x < t) t = x;}
template <class T> void _checkmax(T &t,T x) {if(t==-1) t = x; if(x > t) t = x;}
typedef pair <int,int> PII;
typedef pair <double,double> PDD;
typedef long long ll;
#define foreach(it,v) for(__typeof((v).begin()) it = (v).begin(); it != (v).end ; it ++)
struct S {
    char maze[3][3];
    int x , y;
    int g , h , f;
    S () {}
    S(const S& b) {
        for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            maze[i][j] = b.maze[i][j];
            x=b.x; y=b.y;
            g=b.g; h=b.h; f=b.f;
    }
    friend bool operator < (const S& a,const S& b) {
        if(a.f == b.f) return a.g < b.g;
        return a.f > b.f;
    }
}s;

const int fac[] = {1,1,2,6,24,120,720,5040,40320};
bool vis[363000];
int pre[363000];
char op[363000];

inline int inv_hash(S b) {
    char str[10]; int ans = 0;
    for(int i=0;i<3;i++) {
        for(int j=0;j<3;j++) {
            str[i*3+j] = b.maze[i][j];
            int cnt = 0;
            for(int k=i*3+j-1;k>=0;k--) {
                if(str[k] > str[i*3+j]) cnt ++;
            }
            ans += fac[i*3+j]*cnt;
        }
    }
    return ans;
}

const int pos[][2] = {{0,0},{0,1},{0,2},{1,0},{1,1},{1,2},{2,0},{2,1},{2,2}};
inline int h(S b) {
    int val = 0;
    for(int i=0;i<3;i++) {
        for(int j=0;j<3;j++) {
            if(b.maze[i][j] == 'x') continue;
            int c = b.maze[i][j] - '1';
            val += abs(pos[c][0]-i) + abs(pos[c][1]-j);
        }
    }
    return val;
}

const int dir[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
bool bfs() {
    memset(vis,false,sizeof(vis));
    priority_queue<S> q;
    q.push(s);
    while(!q.empty()) {
        S u = q.top(); q.pop();
        int ihu = inv_hash(u);
        for(int i=0;i<4;i++) {
            S v = u;
            v.x += dir[i][0];
            v.y += dir[i][1];
            if(v.x<0 || v.y<0 || v.x>=3 || v.y>=3) continue;
            v.maze[u.x][u.y] = u.maze[v.x][v.y];
            v.maze[v.x][v.y] = 'x';
            v.g += 1; v.h = h(v); v.f = v.g + v.h;
            int ihv = inv_hash(v);
            if(vis[ihv]) continue;
            vis[ihv] = 1;
            pre[ihv] = ihu;
            if(i == 0) op[ihv] = 'd';
            else if(i == 1) op[ihv] = 'r';
            else if(i == 2) op[ihv] = 'u';
            else if(i == 3) op[ihv] = 'l';
            if(ihv == 0) return true;
            q.push(v);
        }
    }
    return false;
}

inline bool inv_check() {
    char str[10];
    int cnt = 0;
    for(int i=0;i<3;i++) {
        for(int j=0;j<3;j++) {
            str[i*3+j] = s.maze[i][j];
            if(str[i*3+j] == 'x') continue;
            for(int k=i*3+j-1;k>=0;k--) {
                if(str[k] == 'x') continue;
                if(str[k] > str[i*3+j]) cnt ++;
            }
        }
    }
    return !(cnt&1);
}

char in[100];
char stk[100];
int main() {
    while(gets(in)){
        for(int i=0,x=0,y=0;in[i];i++){
            if((in[i]<='9'&&in[i]>='0')||in[i]=='x'){
                s.maze[x][y]=in[i];
                if(in[i]=='x'){s.x=x;s.y=y;}
                y++; if(y==3) y=0,x++;
            }
        }
        if(!inv_check()) {
            puts("unsolvable");
            continue;
        }
        s.g = 0; s.h = h(s); s.f = s.g + s.h;
        int st = inv_hash(s);
        if(st == 0) { puts(""); continue; }
        bfs();
        int top = 0 , en = 0;
        while(en != st) {
            stk[top++] = op[en];
            en = pre[en];
        }
        for(int i=top-1;i>=0;i--) putchar(stk[i]);
        puts("");
    }
    return 0;
}

 

 

 

 

 

转载于:https://www.cnblogs.com/aiiYuu/archive/2013/04/02/2994632.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值