acwing-2060. 奶牛選美
阿新 • • 發佈:2022-01-15
聽說最近兩斑點的奶牛最受歡迎,約翰立即購進了一批兩斑點牛。
不幸的是,時尚潮流往往變化很快,當前最受歡迎的牛變成了一斑點牛。
約翰希望通過給每頭奶牛塗色,使得它們身上的兩個斑點能夠合為一個斑點,讓它們能夠更加時尚。
牛皮可用一個 N×M 的字元矩陣來表示,如下所示:
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....
其中,X 表示斑點部分。
如果兩個 X 在垂直或水平方向上相鄰(對角相鄰不算在內),則它們屬於同一個斑點,由此看出上圖中恰好有兩個斑點。
約翰牛群裡所有的牛都有兩個斑點
約翰希望通過使用油漆給奶牛儘可能少的區域內塗色,將兩個斑點合為一個。
在上面的例子中,他只需要給三個 .. 區域內塗色即可(新塗色區域用 ∗ 表示):
................
..XXXX....XXX...
...XXXX*...XX...
.XXXX..**..XXX..
........XXXXX...
.........XXX....
請幫助約翰確定,為了使兩個斑點合為一個,他需要塗色區域的最少數量。
輸入格式
第一行包含兩個整數 N 和 M。
接下來 N 行,每行包含一個長度為 M 的由 X 和 . 構成的字串,用來表示描述牛皮圖案的字元矩陣。
輸出格式
輸出需要塗色區域的最少數量。
資料範圍
1≤N,M≤50
輸入樣例:
6 16
................
..XXXX....XXX...
...XXXX....XX...
.XXXX......XXX..
........XXXXX...
.........XXX....
輸出樣例:
3
方法一:遍歷兩個斑點的所有可能距離
先分別用兩個vector存兩個斑點上的所有點,遍歷點上的所有曼哈頓距離(|x1-x2|+|y1-y2|),取最小值
寫法一:
一開始還沒理清思路,寫下了這個樂色寫法:先BFS找到一個斑點上的其中一個點,再BFS從該點找到該斑點,再遍歷矩陣找到另一個斑點,最後遍歷計算曼哈頓距離
#include <bits/stdc++.h> using namespace std; struct Node { int x{}, y{}; Node(int x, int y) { this->x = x; this->y = y; } Node() = default;; }; string matrix[51]; bool flag[51][51]; int n, m; int dx[4] = {-1, 1, 0, 0}; int dy[4] = {0, 0, -1, 1}; void pushAdj(queue<Node> &q, Node &node) { for (int i = 0; i < 4; i++) { int a = node.x + dx[i], b = node.y + dy[i]; if (a >= 0 && a < m && b >= 0 && b < n && !flag[b][a]) { q.emplace(a, b); flag[b][a] = true; } } } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) cin >> matrix[i]; // 尋找其中一個斑點 Node node; memset(flag, 0, sizeof(flag)); flag[0][0] = true; queue<Node> q; q.push(Node(0, 0)); while (!q.empty()) { node = q.front(); q.pop(); if (matrix[node.y][node.x] == 'X') break; pushAdj(q, node); } while (!q.empty()) q.pop(); // 獲取兩個斑點 vector<Node> dot1, dot2; memset(flag, 0, sizeof(flag)); q.push(node); while (!q.empty()) { node = q.front(); q.pop(); if (matrix[node.y][node.x] == 'X') { matrix[node.y][node.x] = 'a'; dot1.emplace_back(node.x, node.y); pushAdj(q, node); } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) if (matrix[i][j] == 'X') dot2.emplace_back(j, i); } // 計算最短距離 int res = INT_MAX; for (const auto &d1 : dot1) { for (const auto &d2 : dot2) res = min(res, abs(d1.x - d2.x) + abs(d1.y - d2.y)); } printf("%d", res-1); return 0; }
寫法二:
為了省去BFS帶來的麻煩,使用DFS,在visit結點時,如果是'X'就入隊。最終得到兩個連通分量points[0]和[1],遍歷計算曼哈頓距離
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
string matrix[51];
int n, m;
vector<pii> points[2];
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
void dfs(int x, int y, vector<pii> &point) {
point.emplace_back(x, y);
for (int i = 0; i < 4; i++) {
int a = x + dx[i], b = y + dy[i];
if (a >= 0 && a < n && b >= 0 && b < m && matrix[a][b] == 'X') {
matrix[a][b] = '.';
dfs(a, b, point);
}
}
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++)
cin >> matrix[i];
int k = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
if (matrix[i][j] == 'X')
dfs(i, j, points[k++]);
}
int res = INT_MAX;
for (const auto &d1 : points[0]) {
for (const auto &d2 : points[1])
res = min(res, abs(d1.first - d2.first) + abs(d1.second - d2.second));
}
cout << res - 1;
}
方法二:雙端佇列
TODO