1 专题说明
本专题用来计算使用多源BFS和双端队列BFS求解的题目。
2 训练
题目1:173矩阵距离
考点:多源bfs
C++代码如下,
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N = 1010;
int g[N][N];
int d[N][N];
int n, m;
int main() {
queue<pair<int,int>> q;
memset(d, -1, sizeof d);
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
char c;
cin >> c;
g[i][j] = c - '0';
if (g[i][j]) {
q.push(make_pair(i,j));
d[i][j] = 0;
}
}
}
int dirs[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
while (!q.empty()) {
auto t = q.front();
q.pop();
//t下一步可以走到哪里
for (int k = 0; k < 4; ++k) {
int x = t.first + dirs[k][0];
int y = t.second + dirs[k][1];
if (x < 1 || x > n || y < 1 || y > m) continue;
if (d[x][y] != -1) continue;
q.push(make_pair(x,y));
d[x][y] = d[t.first][t.second] + 1;
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cout << d[i][j] << " ";
}
cout << endl;
}
return 0;
}
题目2:1107魔板
考点:最小步数模型
C++代码如下,
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <string>
using namespace std;
unordered_map<int, int> st;
unordered_map<int,pair<int,char>> map_node_prev;
unordered_map<int,int> d;
int vec2x(vector<vector<int>> vec) {
int x = 0;
for (int i = 0; i < 4; ++i) {
x = x * 10 + vec[0][i];
}
for (int i = 0; i < 4; ++i) {
x = x * 10 + vec[1][3-i];
}
return x;
}
vector<vector<int>> x2vec(int x) {
//x = 12345678
vector<vector<int>> vec(2, vector<int>(4, 0));
vector<int> nums;
while (x > 0) {
nums.emplace_back(x % 10);
x /= 10;
}
//nums = {8, 7, 6, 5, 4, 3, 2, 1};
reverse(nums.begin(), nums.end());
//nums = {1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < 4; ++i) {
vec[0][i] = nums[i];
}
for (int i = 4; i < 8; ++i) {
vec[1][7-i] = nums[i];
}
return vec;
}
int operation_a(int x) {
vector<vector<int>> vec = x2vec(x);
for (int i = 0; i < 4; ++i) {
swap(vec[0][i], vec[1][i]);
}
int nx = vec2x(vec);
return nx;
}
int operation_b(int x) {
vector<vector<int>> vec = x2vec(x);
for (int j = 2; j >= 0; --j) {
swap(vec[0][j], vec[0][j+1]);
swap(vec[1][j], vec[1][j+1]);
}
int nx = vec2x(vec);
return nx;
}
int operation_c(int x) {
vector<vector<int>> vec = x2vec(x);
vector<vector<int>> nvec = vec;
nvec[0][1] = vec[1][1];
nvec[0][2] = vec[0][1];
nvec[1][1] = vec[1][2];
nvec[1][2] = vec[0][2];
int nx = vec2x(nvec);
return nx;
}
int main() {
vector<int> nums(8, 0);
for (int i = 0; i < 8; ++i) cin >> nums[i];
vector<vector<int>> vec(2, vector<int>(4, 0));
for (int i = 0; i < 4; ++i) {
vec[0][i] = nums[i];
}
for (int i = 4; i < 8; ++i) {
vec[1][7-i] = nums[i];
}
int endnode = vec2x(vec);
int startnode = 12345678; //基本状态到特殊状态的路径
queue<int> q;
q.push(startnode);
st[startnode] = true;
d[startnode] = 0;
while (!q.empty()) {
auto t = q.front();
q.pop();
if (t == endnode) {
break;
}
//t可以走到哪里
//operation_a
int ta = operation_a(t);
if (!st[ta]) {
q.push(ta);
st[ta] = true;
map_node_prev[ta] = make_pair(t, 'A');
d[ta] = d[t] + 1;
}
//operation_b
int tb = operation_b(t);
if (!st[tb]) {
q.push(tb);
st[tb] = true;
map_node_prev[tb] = make_pair(t, 'B');
d[tb] = d[t] + 1;
}
//operation_c
int tc = operation_c(t);
if (!st[tc]) {
q.push(tc);
st[tc] = true;
map_node_prev[tc] = make_pair(t, 'C');
d[tc] = d[t] + 1;
}
}
string operations = "";
int t = endnode;
while (t != startnode) {
pair<int, char> prevt = map_node_prev[t];
t = prevt.first;
operations += prevt.second;
}
reverse(operations.begin(), operations.end()); //翻转operations字符串
cout << d[endnode] << endl;
if (d[endnode]) cout << operations << endl;
return 0;
}
bfs可以求出最短路径,该题中,从结点node
走到下一个结点nextnode
有一个优先级(即,优先进行字典序小的操作)。如果按照规定优先级进行操作,那么bfs可以得到最优结点转换的最短路径。
题目3:175电路维修
考点:双端队列广搜。边权只有0和1的图上,求最短路。
C++代码如下,
#include <cstring>
#include <iostream>
#include <algorithm>
#include <deque>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 510, M = N * N;
int n, m;
char g[N][N];
int dist[N][N];
bool st[N][N];
int bfs() {
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[0][0] = 0;
deque<PII> q;
q.push_back({0, 0});
char cs[] = "\\/\\/";
int dx[4] = {-1, -1, 1, 1}, dy[4] = {-1, 1, 1, -1};
int ix[4] = {-1, -1, 0, 0}, iy[4] = {-1, 0, 0, -1};
while (q.size()) {
PII t = q.front();
q.pop_front();
if (st[t.x][t.y]) continue;
st[t.x][t.y] = true;
for (int i = 0; i < 4; ++i) {
int a = t.x + dx[i], b = t.y + dy[i];
if (a < 0 || a > n || b < 0 || b > m) continue;
int ca = t.x + ix[i], cb = t.y + iy[i];
int d = dist[t.x][t.y] + (g[ca][cb] != cs[i]);
if (d < dist[a][b]) {
dist[a][b] = d;
if (g[ca][cb] != cs[i]) q.push_back({a, b});
else q.push_front({a, b});
}
}
}
return dist[n][m];
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i) scanf("%s", g[i]);
int t = bfs();
if (t == 0x3f3f3f3f) puts("NO SOLUTION");
else printf("%d\n", t);
}
return 0;
}