版权声明: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;
}