经典问题:八数码问题(双向BFS)

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

输入输出格式
输入格式:
输入初始状态,一行九个数字,空格用0表示

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

输入输出样例
输入样例#1:
283104765
输出样例#1:
4

#include 
#include 
#include 
#include 
#include 
using namespace std;
const int las=123804765;//状态压缩终状态
//空格与右、左、上、下交换
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
int ma[4][4];//现状态地图
int beg;//初始状态
int zero_x,zero_y;//零的位置
int go_x,go_y;//要交换的位置

//开一个876543211的数组肯定compile error,因此用map记录
map<int,int> dir;
map<int,int> ans;
queue<int> qu;
//双向bfs可节省大量时间
//其使用要求是知道最终状态,适合此题

void pre_work()
{
    scanf("%d",&beg);
    if(beg==las)
    {
        printf("%d\n",0);
        exit(0);
    }
    qu.push(beg);
    qu.push(las);
    //将两头的bfs区分为不同方向
    ans[beg]=0;
    ans[las]=1;
    dir[beg]=1;
    dir[las]=2;
}

void work()
{
    int now,cur;
    while(!qu.empty())
    {
        cur=now=qu.front();
        qu.pop();
        //将now状态分到地图中
        for(int i=3;i>0;i--)
            for(int j=3;j>0;j--)
            {
                ma[i][j]=now%10;
                now/=10;
                if(!ma[i][j])
                {
                    zero_x=i;
                    zero_y=j;
                }
            }
        //空格尝试与上下左右交换
        for(int i=0;i<4;i++)
        {
            go_x=zero_x+dx[i];
            go_y=zero_y+dy[i];
            if(go_x<1||go_x>3||go_y<1||go_y>3) continue;
            swap(ma[zero_x][zero_y],ma[go_x][go_y]);
            now=0;
            //重新将交换后的状态记录为now
            for(int i=1;i<=3;i++)
                for(int j=1;j<=3;j++)
                    now=10*now+ma[i][j];
            //判重:来回走,舍弃
            if(dir[now]==dir[cur])
            {
            	//注意要先交换回来
                swap(ma[zero_x][zero_y],ma[go_x][go_y]);
                continue;
            }
            //如果搜索到了另一边已经搜到的状态
            if(dir[now]+dir[cur]==3)
            {
                printf("%d\n",ans[cur]+ans[now]);
                return;
            }
            //方向不变,路程加一
            ans[now]=ans[cur]+1;
            dir[now]=dir[cur];
            swap(ma[zero_x][zero_y],ma[go_x][go_y]);
            qu.push(now);
        }
    }
}

int main()
{
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
    pre_work();
    work();
    return 0;
}

你可能感兴趣的:(搜索的艺术)