广度优先搜索
上一回我们讲了深度优先搜索,那么这会我们来讲一讲他的好兄弟,也就是bfs
。那么上一回我们知道dfs
是不撞南墙不回头,也就是一条路走到底。但是广搜不一样,他是一层一层的搜索,就是一颗树的样子,第一层是 1 1 1,第二层是 2 , 3 2,3 2,3,第三层是 4 , 5 , 6 , 7 4,5,6,7 4,5,6,7。
那么bfs
的遍历顺序就是1->2/3->4/5/6/7
。所以我们不难看出广搜的一个很好的性质,就是方便找最短路径。所以通常广搜也用来寻找最短的一个路径和长度。那么同时我们换一种方法来考虑,从起点出发,类似于泼水一般,让水流顺着多个方向同时蔓延。这种方法被称为洪泛法。通常也就是使用bfs
来实现的。
那么怎么实现bfs
呢?通常就是使用队列来维护,也就是先进先出的特性。比方说还是上面那张图片。我们就是先把 1 1 1 入队,这是第一步,然后下一步的话就是先把他自己弹出,然后把它下一层的 2 , 3 2,3 2,3 入队,这样就可以保证每次搜索一层了。那么就下来我给大家贴一下模版。
q·push(初始状态);// 将初始状态入队
while (!q.empty()) {state u = q.front();// 取出队首q.pop();//出队for(...) 1/找到u的所有可达状态v更新数据if(...)//v需要满足某些条件,如未访问过、未在队内等q·push(v); // 入队 (同时可能需要维护某些必要信息)
那么接下来我们就来讲一下经典的例题
魔板 Magic Squares
我们知道魔板的每一个方格都有一种颜色。这 8 8 8 种颜色用前 8 8 8 个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } \{1,2,3,4,5,6,7,8\} {1,2,3,4,5,6,7,8} 来表示。这是基本状态。
这里提供三种基本操作,分别用大写字母 A \text A A, B \text B B, C \text C C 来表示(可以通过这些操作改变魔板的状态):
A \text A A:交换上下两行;
B \text B B:将最右边的一列插入最左边;
C \text C C:魔板中央四格作顺时针旋转。
下面是对基本状态进行操作的示范:
A \text A A:
8 7 6 5 8\quad7\quad6\quad5 8765
1 2 3 4 1\quad2\quad3\quad4 1234
B \text B B:
4 1 2 3 4\quad1\quad2\quad3 4123
5 8 7 6 5\quad8\quad7\quad6 5876
C \text C C:
1 7 2 4 1\quad7\quad2\quad4 1724
8 6 3 5 8\quad6\quad3\quad5 8635
对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。
那么这道题目我认为一个难点就在于如何想象到时广搜,那么其实这里可以抽象成一行行字符串代表成为当前的状态。所以我们每一次都是搜索当前进行三种操作的哪一种就可以了。然后我们就需要注意一个坑点:万一回来呢了?也就是说万一通过一些操作,有返回到之前的一个节点上,这就出现死循环了,所以我们需要使用map
来进行一个映射关系,自动去重。那么计算最短操作序列的长度,也就是map
中统计关键字出现的次数,然后输出此长度即可。
用count
函数来判断关键字是否出现,返回值为 0 0 0 或 1 1 1;
输出map
的长度采用size
函数完成;然后就给大家上一份代码,广搜的结构较为模版,代码长的也差不多,就写一道题就好了。
#include<bits/stdc++.h>
using namespace std;
string a;
map<string,string>m;
queue<string>q;
void A(string x)
{string xx=x;for(int i=0;i<4;i++){char x1=x[i];x[i]=x[7-i];x[7-i]=x1;}if(m.count(x)==0){q.push(x);m[x]=m[xx]+'A';}return;
}
void B(string x)
{string xx=x;x[0]=xx[3],x[1]=xx[0],x[2]=xx[1],x[3]=xx[2],x[4]=xx[5],x[5]=xx[6],x[6]=xx[7],x[7]=xx[4];if(m.count(x)==0){q.push(x);m[x]=m[xx]+'B';}return;
}
void C(string x)
{string xx=x;x[1]=xx[6],x[2]=xx[1],x[5]=xx[2],x[6]=xx[5];if(m.count(x)==0){q.push(x);m[x]=m[xx]+'C';}return;
}
void bfs()
{q.push("12345678");m["12345678"]="";while(q.empty()==false){A(q.front());B(q.front());C(q.front());if(m.count(a)!=0){cout<<m[a].size()<<endl<<m[a];return;}q.pop();}return;
}
int main()
{for(int i=0;i<8;i++){char a1;cin>>a1;a+=a1;getchar();}bfs();return 0;
}