【洛谷】P1379 八数码难题(bfs)

题目

题目描述

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

输入输出格式

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

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

输入输出样例

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


分析

对着lrj紫书瞎改改,就A了。


代码

#include<cstdio>
#include<cstring>
#include<set>
using namespace std;

typedef int State[9];
const int MAXSTATE=1000000;
State st[MAXSTATE],goal={1,2,3,8,0,4,7,6,5};
int dist[MAXSTATE];

set<int> vis;
void init_lookup_table() { vis.clear(); }
int try_to_insert(int s)
{
    int v=0;
    for(int i=0;i<9;i++) v=v*10+st[s][i];
    if(vis.count(v)) return 0;
    vis.insert(v);
    return 1;
}

const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
int bfs()
{
    init_lookup_table();
    int front=1,rear=2;
    while(front<rear)
    {
        State& s=st[front];
        if(memcmp(goal,s,sizeof(s))==0) return front;
        int z;
        for(z=0;z<9;z++) if(!s[z]) break;
        int x=z/3,y=z%3;
        for(int d=0;d<4;d++)
        {
            int newx=x+dx[d];
            int newy=y+dy[d];
            int newz=newx*3+newy;
            if(newx>=0 && newx<3 && newy>=0 && newy<3)
            {
                State& t=st[rear];
                memcpy(&t,&s,sizeof(s));
                t[newz]=s[z];
                t[z]=s[newz];
                dist[rear]=dist[front]+1;
                if(try_to_insert(rear)) rear++;
            }
        }
        front++;
    }
    return 0;
}

int main()
{
    char s[15];
    scanf("%s",s);
    for(int i=0;i<9;i++)
        st[1][i]=s[i]-'0';
//	for(int i=0;i<9;i++) printf(" %d ",st[1][i]); 
    int ans = bfs();
    printf("%d\n", dist[ans]);
    return 0;
}
posted @ 2017-12-16 16:53  noble_(noblex)  阅读(298)  评论(0编辑  收藏  举报
/* */