【ybtoj】【BFS】【例題5】電路維修
阿新 • • 發佈:2021-02-01
【例題5】電路維修
Link
解題思路
每一根電線有四種情況(●是電連到哪)
每一種情況的下一根電線連線座標變化,和下一根電線的狀態提前預處理出來
舉個栗子
對於每一根電線,嘗試往它可連線三條電線擴充套件
如果和預期電線不一樣,就翻轉電線
對於預期電線和實際電線的比較
我把方向相同的電線的編號統為偶數和奇數了(沒想到吧)
關於BUG
程式是有一點小問題,所以導致有幾個“NO SOLUTION”的情況也出現答案
HKY巨爺找到規律
(
n
+
m
)
%
2
=
0
(n+m)\%2=0
(n+m) %2=0有解
(
n
+
m
)
%
2
=
1
(n+m)\%2=1
(n+m)%2=1無解
然後我懶得改程式,直接用規律過資料了
Code
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int way[4][3][3] = { { { -1, -1, 0 }, { -1, 0, -1 }, { 0, 1, 3 } },
{ { -1, -1, 0 }, { 0, 1, 1 } , { 0, 1, 2 } },
{ { 0, 1, 1 }, { 1, 0, 1 }, { 1, 3, 2 } },
{ { 0, 1, 1 }, { -1, -1, 0 }, { 0, 3, 2 } } };
struct DT{
int x, y, k;
}now;
int T, n, m, a[510][510], v[510][510];
queue<DT> q;
char c;
bool check(int x, int y) { return (x > 0 && x <= n && y > 0 && y <= m); }
void BFS() {
q.push((DT){1, 1, 2});
memset(v, 0x7f, sizeof(v));
v[1][1] = a[1][1];
while (!q.empty()) {
now = q.front();
if (v[now.x][now.y] >= v[n][m]) {//如果當前翻轉次數已經超過了當前答案,不需要往下做了
q.pop();
continue;
}
for (int i = 0; i < 3; i++) {
int xx = now.x + way[now.k][0][i], yy = now.y + way[now.k][1][i], kk = way[now.k][2][i];
if (!check(xx, yy)) continue;
if ((kk % 2) == (a[xx][yy] % 2)) {//相同
if (v[now.x][now.y] < v[xx][yy]) {//類似SPFA的路徑鬆弛
v[xx][yy] = v[now.x][now.y];
if ((xx != n || yy != m) && (xx != 1 || yy != 1))
q.push((DT){xx, yy, kk});
}
} else {//不相同,需要翻轉
if ((v[now.x][now.y] + 1) < v[xx][yy]) {
v[xx][yy] = v[now.x][now.y] + 1;
if ((xx != n || yy != m) && (xx != 1 || yy != 1))
q.push((DT){xx, yy, kk});
}
}
}
q.pop();
}
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
cin >> c;
if (c == '/')
a[i][j] = 1;
}
BFS();
if ((n + m) % 2)//規律過資料
printf("NO SOLUTION\n");
else
printf("%d\n", v[n][m]);
}
}