例题:P1397 八数码难题

###双向BFS

普通BFS

双向BFS

所谓双向广度优先搜索指的是搜索沿两个方向同时进行

正向搜索:从初始点向目标点搜索;

逆向搜索:从目标点向初始点搜索;

从正反两个方向搜索,理论上可以节省二分之一的搜索量,从而提高搜索速度,节约内存空间。

从初始状态和目标状态向两个方向同时进行扩展,如果两颗解答树在某个节点发生一次重合,即可终止此搜索过程,则该节点所连接的两条路径所拼成的路径就是最优解

●双向广度优先搜索通常有两种搜索方法:

①、两个方向交替扩展;

②、选择结点个数较少的那个方向先扩展;

●实现方法:

建立两个队列分别拓展两个方向出发的状态。

每次while循环时只扩展正反两个方向中节点数目较少的一个,可以使两边的发展速度保持一定的平衡,从而减少总扩展节点的个数,加快搜索速度。

例题代码

#include<iostream>
#include<map>
#include<queue>
#include<cstring>
using namespace std;
map<string, int> ma,mb;
struct nod
{
string a;
int x, y;
};
queue<nod> qa,qb;
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};

int main()
{
string aim = "123804765",a;
cin >> a;
if(a==aim)
{
cout << "0";
return 0;
}
for (int i = 0; i < 9;i++)
{
if(a[i]=='0')
qa.push({a, i / 3, i % 3});
}
qb.push({aim, 1, 1});
ma[a] = mb[aim] = 0;
while(!qa.empty()||!qb.empty())
{
if(qa.size()<qb.size())
{
string temp = qa.front().a;
int x1 = qa.front().x;
int y1 = qa.front().y;
qa.pop();
for (int i = 0; i < 4;i++)
{
if(x1+dx[i]<0||x1+dx[i]>2||y1+dy[i]<0||y1+dy[i]>2)
continue;
string b = temp;
swap(b[x1 * 3 + y1], b[(x1 + dx[i]) * 3 + y1+dy[i]]);
if(ma[b]!=0)
continue;
if(mb[b]!=0)
{
cout << ma[temp] + mb[b] + 1;
return 0;
}
ma[b] = ma[temp] + 1;
qa.push({b, x1 + dx[i], y1 + dy[i]});
}
}
else
{
string temp = qb.front().a;
int x1 = qb.front().x;
int y1 = qb.front().y;
qb.pop();
for (int i = 0; i < 4;i++)
{
if(x1+dx[i]<0||x1+dx[i]>2||y1+dy[i]<0||y1+dy[i]>2)
continue;
string b = temp;
swap(b[x1 * 3 + y1], b[(x1 + dx[i]) * 3 + y1+dy[i]]);
if(mb[b]!=0)
continue;
if(ma[b]!=0)
{
cout << ma[b] + mb[temp] + 1;
return 0;
}
mb[b] = mb[temp] + 1;
qb.push({b, x1 + dx[i], y1 + dy[i]});
}
}
}
return 0;
}

###双端队列BFS

P4667 [BalticOI 2011 Day1]Switch the Lamp On

类似优先队列优化的d j最短路,每次用未被标记最小的值去更新其他点。

边权只有0、1,可用双端队列代替优先队列

边权为0,插到队头;边权为1,插入队尾,这样就省去了排序操作,保证队首最小

例题代码

#include<deque>
#include<cstring>
#include<iostream>
using namespace std;
struct nod
{
int x, y;
};
char sq[505][505];
deque<nod> q;
int dx[4] = {1, 1, -1, -1};
int dy[4] = {1, -1, 1, -1};
int rx[4] = {0, 0, -1, -1};
int ry[4] = {0, -1, 0, -1};
char ch[5] = "\\//\\";
bool vis[505][505];
int dist[505][505];
int n, m;

void bfs()
{
memset(vis, 0, sizeof(vis));
memset(dist, 0x3f, sizeof(dist));
q.push_front({0, 0});
dist[0][0] = 0;
while(!q.empty())
{
int x1 = q.front().x;
int y1 = q.front().y;
q.pop_front();
if(vis[x1][y1])
continue;
vis[x1][y1] = 1;
for (int i = 0; i < 4;i++)
{
int x2 = x1 + dx[i];
int y2 = y1 + dy[i];
if(x2<0||x2>n||y2<0||y2>m)
continue;
int xs = x1 + rx[i];
int ys = y1 + ry[i];
int d = dist[x1][y1];
if(sq[xs][ys]!=ch[i])
d++;
if(d<dist[x2][y2])
{
dist[x2][y2] = d;
if(sq[xs][ys]!=ch[i])
q.push_back({x2, y2});
else
q.push_front({x2, y2});
}
}
}
}

int main()
{
cin >> n >> m;
for (int i = 0; i < n;i++)
{
for (int j = 0; j < m;j++)
cin >> sq[i][j];
}
bfs();
if(dist[n][m]==0x3f3f3f3f)
cout << "NO SOLUTION"<<endl;
else
cout << dist[n][m]<<endl;
return 0;
}