1. 程式人生 > 其它 >【ybtoj】【BFS】【例題5】電路維修

【ybtoj】【BFS】【例題5】電路維修

技術標籤:ybtoj搜尋

【例題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]); } }