Files
python/TangDou/AcWing/ErFenTu/POJ3020.md
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

100 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

##[$POJ$ $3020$ $Antenna$ $Placement$](http://poj.org/problem?id=3020)
### 一、题目描述
*--代表城市,o--代表空地
给城市安装无线网,一个无线网最多可以覆盖两座城市,问覆盖所有城市最少要用多少无线。
**公式:最小路径覆盖 = 总节点数-最大匹配数**
我们要尽可能多的建立能覆盖两个城市的基站(二分匹配最大匹配),剩下的城市每个城市建立一个基站。
### 二、$Code$
```cpp {.line-numbers}
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <cstring>
#include <vector>
#include <stack>
#include <cstdio>
using namespace std;
const int N = 50, M = N * N;
char a[N][N]; // 原始矩阵
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int dx[] = {-1, 0, 1, 0}; // 上右下左
int dy[] = {0, 1, 0, -1}; // 上右下左
int n, m; // n行m列
// 匈牙利算法
int st[M], match[M];
int dfs(int u) {
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (st[v]) continue;
st[v] = 1;
if (match[v] == -1 || dfs(match[v])) {
match[v] = u;
return 1;
}
}
return 0;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("POJ3020.in", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
// 初始化链式前向星
memset(h, -1, sizeof h);
idx = 0;
scanf("%d %d", &n, &m); // n*m的矩阵
for (int i = 1; i <= n; i++) scanf("%s", a[i] + 1); // 使用char[],按行一次读入,快捷!
int cnt = 0; // 城市个数
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
//*--代表城市,o--代表空地
// 给城市安装无线网,一个无线网最多可以覆盖两座城市,问覆盖所有城市最少要用多少无线网。
if (a[i][j] == '*') {
cnt++;
// 四周探测
for (int k = 0; k < 4; k++) {
int tx = i + dx[k], ty = j + dy[k];
if (tx < 1 || tx > n || ty < 1 || ty > m) continue;
// 城市到城市建边,无向图,尽量让无线网构建在两个城市上,这样才能省资源,要不一个城市一个无向网太费了
if (a[tx][ty] == '*') add((i - 1) * m + j, (tx - 1) * m + ty);
}
}
}
}
// 匈牙利
memset(match, -1, sizeof match);
int res = 0;
for (int i = 1; i <= n * m; i++) {
memset(st, 0, sizeof st);
if (dfs(i)) res++;
}
// 无向图,重复计算,然后除以2,就是最大匹配数
printf("%d\n", cnt - res / 2);
}
return 0;
}
```