题目链接:http://poj.org/problem?id=1077
这个用BFS、双向BFS、Astar都能解决,这里先用双向BFS来做。
因为要输出路径,多以不能直接用STL中的queue容器,不然出队后就找不到了,所以就自己封装了一个队列,用数组模拟的,还增加了输出路径的功能,留下来当做模板来用。
这里让空格走四个方向,把状态按照题目给的方式排成一列,用康拓展开来记录状态,用两个队列同时从起点和终点出发,搜索四个方向,如果碰到在一个队列搜索到的新状态在另一个队列中出现过,这个时候就可以输出路径了。
要注意的是在逆向搜索的队列中所有的方向都是反的,注意 u 和 d 对换,l 和 r 对换。
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
const int fac[9] = {1,1,2,6,24,120,720,5040,40320};
const int dx[4] = {-1,0,1,0};
const int dy[4] = {0,1,0,-1};
struct node
{
char state[12];
int pos;
int pre;
char c;
};
node st, ed;
int a[10];
int b[10] = {9,1,2,3,4,5,6,7,8,0};
int f[400000];
int g[400000];
struct Queue //自己封装的队列
{
node q[400000];
int Size;
int head, tail;
Queue()
{
Size = 0;
head = tail = 0;
}
node front()
{
return q[head];
}
int indxHead()
{
return head;
}
int indextail()
{
return tail-1;
}
void pop()
{
head++;
}
void push(node a)
{
q[tail++] = a;
}
bool empty()
{
return head == tail;
}
void Find(int x, bool order) //输出路径的函数,order表示是否是顺序的队列
{
if (order) //顺序队列的路径输出
{
char path[1000] = {0};
int cnt = 0;
while (q[x].pre != -1)
{
path[cnt++] = q[x].c;
x = q[x].pre;
}
for (int i=cnt-1; i>=0; i--)
printf("%c",path[i]);
}
else //逆序队列的输出
{
while (q[x].pre != -1)
{
printf("%c",q[x].c);
x = q[x].pre;
}
}
}
}Q,P; //Q是顺序队列,P事逆序队列
int contor(char *a, int n) //康拓展开,序列映射成数字
{
int sum = 0;
for (int i=1; i<=n; i++)
{
int cnt = 0;
for (int j=i+1; j<=n; j++)
if (a[j] < a[i]) cnt++;
sum += cnt*fac[n-i];
}
return sum;
}
bool next(node& now, int i,int pre, bool order = true) //计算状态now按照某个方向走之后的状态
{
int nowi = (now.pos-1)/3+1;
int nowj = now.pos-(nowi-1)*3;
int newi = nowi+dx[i];
int newj = nowj+dy[i];
if (newi < 1 || newi > 3 || newj < 1 || newj > 3)
return false;
int newpos = (newi-1)*3+newj;
char c = now.state[now.pos]; now.state[now.pos] = now.state[newpos]; now.state[newpos] = c;
now.pos = newpos;
now.pre = pre;
switch (i)
{
case 0:now.c = order ? 'u' : 'd'; break;
case 1:now.c = order ? 'r' : 'l'; break;
case 2:now.c = order ? 'd' : 'u'; break;
case 3:now.c = order ? 'l' : 'r'; break;
}
return true;
}
void BFS() //双向BFS
{
Q.push(st);
P.push(ed);
f[contor(st.state,9)] = 1;
f[contor(ed.state,9)] = 2;
while (!Q.empty() && !P.empty())
{
if (!Q.empty())
{
node now = Q.front();
node tmp = now;
Q.pop();
for (int i=0; i<4; i++)
if (next(now,i,Q.indxHead()-1))
{
node New = now;
now = tmp;
int newState = contor(New.state,9);
if (f[newState] == 2)
{
Q.push(New);
Q.Find(Q.indextail(),true);
P.Find(g[newState],false);
printf("\n");
return;
}
else if (f[newState] == 0)
{
Q.push(New);
f[newState] = 1;
g[newState] = Q.indextail();
}
}
}
if (!P.empty())
{
node now = P.front();
node tmp = now;
P.pop();
for (int i=0; i<4; i++)
if (next(now,i,P.indxHead()-1,false))
{
node New = now;
now = tmp;
int newState = contor(New.state,9);
if (f[newState] == 1)
{
P.push(New);
Q.Find(g[newState],true);
P.Find(P.indextail(),false);
printf("\n");
return;
}
else if (f[newState] == 0)
{
P.push(New);
f[newState] = 2;
g[newState] = P.indextail();
}
}
}
}
}
int main()
{
string s;
getline(cin,s);
a[0] = 0;
int cnt = 0;
for (int i=0; i<s.size(); i++)
{
if (s[i] == ' ') continue;
cnt++;
if (s[i] >= '1' && s[i] <='8')
st.state[cnt] = s[i];
else if (s[i] == 'x')
{
st.state[cnt] = '0';
st.pos = cnt;
}
}
st.pre = -1;
for (int i=1; i<=8; i++) ed.state[i] = '0' + i;
ed.state[9] = '0';
ed.pos = 9;
ed.pre = -1;
BFS();
return 0;
}