農田為 M×N 格網,每格有一種管道 (A~K 11 種)。管道有固定開口方向 (上下左右)。
水源放置於格中心,水沿管道流動可灌溉經過的格子。
求最少需要幾個水源才能灌溉整個農田 (即連通塊數量)。
11 種管道開口配置 (上右下左):
// 索引 0=A, 1=B, ..., 10=K
// up, right, down, left
int up[11] = {1,1,0,0,1,0,1,1,0,1,1};
int right[11] = {0,1,0,1,0,1,1,0,1,1,1};
int down[11] = {0,0,1,1,1,0,0,1,1,1,1};
int left[11] = {1,0,1,0,0,1,1,1,1,0,1};
例如 A(0):上、左開口;K(10):四面皆通。
兩相鄰格子連通需雙向開口:
right 且鄰居 leftleft 且鄰居 rightdown 且鄰居 upup 且鄰居 down#includeusing namespace std; const int MAX = 55; char grid[MAX][MAX]; bool vis[MAX][MAX]; int M, N; int up[11] = {1,1,0,0,1,0,1,1,0,1,1}; int rt[11] = {0,1,0,1,0,1,1,0,1,1,1}; int dn[11] = {0,0,1,1,1,0,0,1,1,1,1}; int lt[11] = {1,0,1,0,0,1,1,1,1,0,1}; int dx[4] = {0, 0, 1, -1}; int dy[4] = {1, -1, 0, 0}; void dfs(int x, int y) { if (vis[x][y]) return; vis[x][y] = true; int cur = grid[x][y] - 'A'; for (int dir = 0; dir < 4; ++dir) { int nx = x + dx[dir], ny = y + dy[dir]; if (nx < 0 || nx >= M || ny < 0 || ny >= N) continue; int nxt = grid[nx][ny] - 'A'; bool connected = false; if (dir == 0) connected = rt[cur] && lt[nxt]; // 右 else if (dir == 1) connected = lt[cur] && rt[nxt]; // 左 else if (dir == 2) connected = dn[cur] && up[nxt]; // 下 else connected = up[cur] && dn[nxt]; // 上 if (connected) dfs(nx, ny); } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); while (cin >> M >> N, M > 0 && N > 0) { for (int i = 0; i < M; ++i) cin >> grid[i]; memset(vis, 0, sizeof(vis)); int ans = 0; for (int i = 0; i < M; ++i) for (int j = 0; j < N; ++j) if (!vis[i][j]) { ++ans; dfs(i, j); } cout << ans << "\n"; } return 0; }
O(M×N),每格最多訪問一次O(M×N) 訪問標記陣列輸入: 2 2 DK HF 3 3 ADC FJK IHE -1 -1 輸出: 2 3
樣例 2 解析:
ADC
FJK
IHE
形成 3 個獨立連通區域 (紅點標示水源位置)。