Vijos1360[八数码问题] 搜索

背景

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.

描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

格式

输入格式

输入初试状态,一行九个数字,空格用0表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

样例1

样例输入1

283104765

样例输出1

4

solution:搜索

#include <set>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int endi[4][4]={0,0,0,0,0,1,2,3,0,8,0,4,0,7,6,5};
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};

struct Matrix{
    int m[4][4];
    Matrix(int s[4][4] ){
        for ( int i=1; i<=3; i++ )
            for ( int j=1; j<=3; j++ )
                m[i][j]=s[i][j];
    }
    bool operator<(const Matrix& s) const{
        for ( int i=1; i<=3; i++ )
            for ( int j=1; j<=3; j++ )
                if( m[i][j]!=s.m[i][j] )
                    return m[i][j]<s.m[i][j];
        return 0;
    }
    Matrix(){}
};

struct Point{
    int x, y, h, f, cnt;
    int m[4][4];
    bool operator<(const Point& s) const {
        return f>s.f;
    }
    Point(){}
}sp;

priority_queue<Point> Q;
set<Matrix> S;

bool in(int x, int y){
    return (x>=1 && x<=3 && y>=1 && y<=3 );
}
int bfs(Point po){
    Q.push(po);
    Matrix t1(po.m);
    S.insert(t1);
    int step=-1;
    while( !Q.empty() ){
        Point tmp=Q.top();
        Q.pop();
        Matrix t2(tmp.m);
        if( step!=-1 && tmp.cnt>step ) continue;
        if( tmp.h==0 ) step=tmp.cnt;
        if( tmp.cnt>105 ) return -1;
        for ( int i=0; i<4; i++ ){
            Point tp=tmp;
            tp.x=tmp.x+dx[i], tp.y=tmp.y+dy[i];
            tp.cnt=tmp.cnt+1;
            if( in(tp.x,tp.y) ){
                int cnt=0;
                swap( tp.m[tp.x][tp.y], tp.m[tmp.x][tmp.y] );
                for ( int i=1; i<=3; i++ )
                    for ( int j=1; j<=3; j++ )
                        if( tp.m[i][j]!=endi[i][j] ) cnt++;
                tp.h=cnt;
                tp.f=tp.h+tp.cnt;
                Matrix t3(tp.m);
                if( S.find(t3)==S.end() ){
                    S.insert(t3);
                    Q.push(tp);
                }
            }
        }
    }
    return step;
}
int main(){
    int z=0;
    for ( int i=1; i<=3; i++ )
        for ( int j=1; j<=3; j++ ){
            scanf("%1d", &sp.m[i][j] );
            if( !sp.m[i][j] ) sp.x=i, sp.y=j;
            else if( sp.m[i][j]!=endi[i][j] ) z++;
        }
    sp.h=sp.f=z;
    sp.cnt=0;
    printf("%d", bfs(sp) );
    return 0; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值