洛谷 P1379 八数码难题

版权声明:EL PSY CONGROO ! https://blog.csdn.net/THIS_IS_HPQ/article/details/81087110

题目描述

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1:

283104765

输出样例#1:

4

一道非常经典的搜索题

通常在面对打暴力搜索题时,我们通常要面对一个问题:

DFS还是BFS?

有些题目,DFS和BFS区别不大,而且DFS在代码上更加简单明了,合理运用DFS可以取得更好的效果。

但是如果我们需要求出最短方案,最短路径时(不是图论求最短路!!!)。

如果运用DFS,我们每次要沿着一条路径搜到边界才会返回,并且我们不知道哪条路才是最短的。

所以要跑完所有路径才能得到最佳方案。这显然既耗时间又容易爆栈。

那么,有没有什么方法能让我们更好的求出最佳方案呢?

当然有啦!(LEX发电语气)

用BFS,我们能枚举出从原点开始,每一次操作所能达到的结果,如果是求最佳方案或者最短路径的话,

那么第一次搜到这个点时,此时的方案数就是最优的!(某些题目如洛谷的P3956这种除外)

让我们回到这道题,显然是用BFS。

但是让人苦恼的是如何判重。

我在这里用了一种很笨的方法——STL——MAP。

将棋盘上的数排成一个字符串,再用MAP将字符串映射成数字(当然也需要用数字来映射成字符串),用来做BFS。

至于棋盘的变换依旧在字符串上操作,只需要一些简单的判定就能完成。

令人尴尬的是由于STL+搜索,程序会变得很慢,开个O2勉强可以接受。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<map>
using namespace std;
#define DEBUG 0
string s,end="123804765";//"end"是终止条件
map<string,int>m;
map<int,string>n;//用MAP构造两个映射
int tot=0,pos;//"pos"表示字符串中'0'的位置。
void bfs()//广搜
{
    int head=1,tail=1;
    int q[1000001][2];
    q[head][0]=1;
    q[head][1]=0;//设置初始状态
    while(head<=tail)
    {	
        string str=n[q[head][0]];
        for(int j=0;j<9;j++)//找到'0'的位置
        if(str[j]=='0')
        {
            pos=j;
            break;
        }	
        string st;
        for(int i=1;i<=4;i++)//4种方向改变'0'的位置
        {
            st=str;
            if(st==end)
            {
                cout<<q[head][1]+1;
                return ;
            }
            if(i==1&&pos>=3)//判断'0'是否能向上移
            {
                swap(st[pos],st[pos-3]);
                if(st==end)
                {
                    cout<<q[head][1]+1;
                    return ;
                }
                else if(!m.count(st))//判重
                {
                    if(DEBUG) cout<<st<<' '<<pos<<endl;
                    m[st]=++tot;
                    n[tot]=st;
                    q[++tail][0]=tot;
                    q[tail][1]=q[head][1]+1;
                }
            }
            else if(i==2&&(pos%3)>=1)//判断'0'是否能向左移
            {
                swap(st[pos],st[pos-1]);
                if(st==end)
                {
                    cout<<q[head][1]+1;
                    return ;
                }
                else if(!m.count(st))
                {
                    if(DEBUG) cout<<st<<' '<<pos<<endl;
                    m[st]=++tot;
                    n[tot]=st;
                    q[++tail][0]=tot;
                    q[tail][1]=q[head][1]+1;
                }
            }
            else if(i==3&&(pos%3)<2)//判断'0'是否能向右移
            {
                swap(st[pos],st[pos+1]);
                if(st==end)
                {
                    cout<<q[head][1]+1;
                    return ;
                }
                else if(!m.count(st))
                {
                    if(DEBUG) cout<<st<<' '<<pos<<endl;
                    m[st]=++tot;
                    n[tot]=st;
                    q[++tail][0]=tot;
                    q[tail][1]=q[head][1]+1;
                }
            }
            else if(i==4&&pos<6)//判断'0'是否能向下移
            {
                swap(st[pos],st[pos+3]);
                if(st==end)
                {
                    cout<<q[head][1]+1;
                    return ;
                }
                else if(!m.count(st))
                {
                    if(DEBUG) cout<<st<<' '<<pos<<endl;
                    m[st]=++tot;
                    n[tot]=st;
                    q[++tail][0]=tot;
                    q[tail][1]=q[head][1]+1;
                }
            }
        }
        head++;
    }
}
int main()
{
    cin>>s;
    if(s==end)//特判一下
    {
        puts("0");
        return 0;
    }
    m[s]=++tot;
    n[tot]=s;
    bfs();	
    return 0;
}

猜你喜欢

转载自blog.csdn.net/THIS_IS_HPQ/article/details/81087110