八数码问题 bfs+map

八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。(用0表示空格)


思路:把八数码问题归结为图上的最短路问题。开始状态对应起点,目标状态对应终点。用广搜去搜索就可以了。

   用STL的map来判重。也可以用set来判重。我看其他大神的博客说用hash表来判重会更快,还有用双向搜索来做的,有兴趣的可以自己写写。

http://www.cnblogs.com/FreeDestiny/archive/2011/10/27/2226709.html  


<pre name="code" class="cpp">#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <stack>
#include <queue>
#include <list>
#include <set>
#define LL long long
#define INF 0x7fffffff
#define FIN 0x80000000
using namespace std;
typedef int State[9];
State st[500000],gold;
int dist[500000];
map<int,int> mp;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
bool ispan(int k)
{
    int res=0;
    for(int i=0;i<9;i++) res=res*10+st[k][i];
    if(mp[res]) return false;
    mp[res]=1;
    return true;
}
int bfs()
{
    queue<int> que;
    que.push(1);
    ispan(1);
    int u=2;
    while(que.size())
    {
        int v=que.front(); que.pop();
        State &s=st[v];
//        for(int i=0;i<9;i++) printf("%d ",s[i]); printf("\n");
        if(memcmp(s,gold,sizeof(State))==0) return v;
        int x,y,z;
        for(z=0;z<9;z++) if(s[z]==0) break;
        x=z/3; y=z%3;
        for(int i=0;i<4;i++)
        {
            int nx=x+dx[i];
            int ny=y+dy[i];
            int nz=nx*3+ny;
            if(nx>=0&&nx<3&&ny>=0&&ny<3)
            {
                State &t=st[u];
                memcpy(&t,&s,sizeof(State));
                t[nz]=s[z];
                t[z]=s[nz];
                dist[u]=dist[v]+1;
                if(ispan(u))
                {
                    que.push(u);
                    u++;
                }
            }
        }
    }
    return -1;
}
int main()
{
    for(int i=0;i<9;i++) scanf("%d",&st[1][i]);
    for(int i=0;i<9;i++) scanf("%d",&gold[i]);
    int ans=bfs();
    printf("%d",ans==-1?ans:dist[ans]);
}
/*
1 2 3 4 5 6 7 8 0
8 7 6 5 4 3 2 1 0

2 6 4 1 3 7 0 5 8
8 1 5 7 3 6 4 0 2

正确输出对应是 30、 31
*/

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值