普通的bfs:解决边权为1的最短路问题。从0的点开始往后更新,因为边权为1,所以呈现单调不递减的趋势。

第一次碰到的距离一定是最短距离,如果边权不相等,不一定是单调不递减趋势,第一次碰到的距离不一定是最短距离。
01BFS又称双端队列BFS
既有0,又有1,能不能用BFS来解决呢?在最短路问题中,边权值可能为1也可能为0。那么,在BFS的过程中,
- 可以将边权为0 的扩展出来的点放到队首,
- 边权为1 扩展出来的点放到队尾。
这样就能保证像普通BFS一样整个队列权值单调不下降。
相同的点可能会多次遇到,此时要进行松弛操作,比如从A->B,从A->C->E->B,这两条路线都能到达B,此时要判断哪一条的路线是最优解。

cpp
#include <iostream>
#include <deque>
#include <cstring>
using namespace std;
const int N = 510;
typedef pair<int, int> PII;
int n, m;
int b1, b2, e1, e2;
char a[N][N];
int st[N][N];
int dx[] = {0, -1, 0, 1};
int dy[] = {1, 0, -1, 0};
int bfs()
{
if (b1 == e1 && b2 == e2) return 0;
deque<PII> q;
memset(st, -1, sizeof(st));
st[b1][b2] = 0;
q.push_front({b1, b2});
while(q.size())
{
auto t = q.front(); q.pop_front();
int x1 = t.first, y1 = t.second;
for (int i = 0; i < 4; i++)
{
int x2 = x1 + dx[i], y2 = y1 + dy[i];
if (x2 < 1 || y2 < 1 || x2 > n || y2 > m) continue;
int cnt = 0;
if (a[x1][y1] == a[x2][y2])
{
cnt = 0;
}
else
{
cnt = 1;
}
if (st[x2][y2] == -1)//如果等于-1
{
st[x2][y2] = st[x1][y1] + cnt;
if (cnt == 0)
{
q.push_front({x2, y2});
}
else
{
q.push_back({x2, y2});
}
}
else
{
if (st[x1][y1] + cnt < st[x2][y2])
{
st[x2][y2] = st[x1][y1] + cnt;
}
}
if (x2 == e1 && y2 == e2) return st[e1][e2];
}
}
return -1;
}
int main()
{
while(cin >> n >> m, n && m)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> a[i][j];
}
}
cin >> b1 >> b2 >> e1 >> e2;
b1++, b2++, e1++, e2++;
cout << bfs() << endl;
}
return 0;
}
为什么第一次走到的一定是最短路径?边权不是0和1吗?
0-1 BFS(双端队列BFS)的核心性质保证了这一点:
队列的单调性
- 在0-1 BFS中,我们使用双端队列(deque)
- 当边权为0时,节点放入队首
- 当边权为1时,节点放入队尾
这样的操作保证了队列中的距离值(st值)是单调不递减的。