[AcWing 175] 电路维修




双端队列 BFS
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 500 + 10;
const int INF = 0x3f3f3f3f;
#define x first
#define y second
int n, m;
char g[N][N];
int d[N][N];
bool st[N][N];
string cs = "\\//\\";
int dx[] = {-1, -1, 1, 1}, dy[] = {-1, 1, -1, 1};
int ix[] = {-1, -1, 0, 0}, iy[] = {-1, 0, -1, 0};
int bfs()
{
memset(d, 0x3f, sizeof d);
memset(st, false, sizeof st);
deque<pair<int,int>> q;
q.push_back({0, 0});
d[0][0] = 0;
while (q.size()) {
auto 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 w = g[ca][cb] != cs[i];
int dist = d[t.x][t.y] + w;
if (dist < d[a][b]) {
d[a][b] = dist;
if (w == 1)
q.push_back({a, b});
else
q.push_front({a, b});
}
}
}
return d[n][m];
}
void solve()
{
cin >> n >> m;
for (int i = 0; i < n; i ++)
for (int j = 0; j < m; j ++)
cin >> g[i][j];
int t = bfs();
if (t == INF)
cout << "NO SOLUTION" << endl;
else
cout << t << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T --) {
solve();
}
// solve();
return 0;
}
- 对于一个位置的字符,有两种状态,右下倾斜和左下倾斜,如果该位置的倾斜方向和输入相同,说明不需要旋转,权值记为 \(0\),否则说明需要旋转,权值记为 \(1\),所有权值为 \(0\) 的点都放到双端队列的头部,权值为 \(1\) 的点都放到双端队列的尾部
- 区分两类坐标,第一类坐标对应的是网格上的点,第二类坐标对应的是输入的字符,对于一个输入的字符,实际上对应了四个网格上的点,对于第一类坐标,能到的点为 \((x - 1, y - 1), (x - 1, y + 1), (x + 1, y - 1), (x + 1, y + 1)\),对于第二类坐标,需要把第一类坐标映射到输入字符坐标上,对于一个网格交点 \((x, y)\),能够映射到的坐标为 \((x - 1, y - 1), (x - 1, y), (x, y - 1), (x, y)\),对应的倾斜方向分别为 右下,左下,左下,右下
第一类坐标

第二类坐标


浙公网安备 33010602011771号