该题主要用的思想在于图的最小点集覆盖等于边的最大匹配数。按照行以及列进行重新计数,然后按照匈牙利算法求出结果即可,具体实现见如下代码:
#include<iostream>
#include<vector>
#include<string>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<deque>
#include<functional>
using namespace std;
int match[2510];
int area2[2510][2510];
bool visit[2510];
class Solve{
public:
int X, Y, P, W;//习惯性假设X*Y,下标还是从1开始的
int area[110][110];//0 空地 1 兴趣 2 障碍
pair<int, int> M[110][110];
int total_r, total_c;
void Init(){
total_r = 0;
total_c = 0;
memset(area2, 0, sizeof(area2));
memset(area, 0, sizeof(area));
cin >> X >> Y >> P;
for (int i = 0; i < P; i++){//兴趣
int a, b;
cin >> a >> b;
area[a][b] = 1;
}
cin >> W;
for (int i = 0; i < W; i++){//障碍
int a, b;
cin >> a >> b;
area[a][b] = 2;
}
for (int i = 1; i <= X; i++){
bool flag = true;
for (int j = 1; j <= Y; j++){
if (area[i][j] == 1){
if (flag){
total_r++; flag = false;
}
M[i][j].first = total_r;
}
if (area[i][j] == 2) flag = true;
}
}
for (int j = 1; j <= Y; j++){
bool flag = true;
for (int i = 1; i <= X; i++){
if (area[i][j] == 1){
if (flag){
total_c++; flag = false;
}
M[i][j].second = total_c;
}
if (area[i][j] == 2) flag = true;
}
}
}
bool dfs(int i){
for (int j = 1; j <= Y; j++){
if (area2[i][j] && !visit[j]){
visit[j] = true;
if (match[j] == -1 || dfs(match[j])){
match[j] = i;
return true;
}
}
}
return false;
}
void Deal(){
Init();
int ans = 0;
for (int i = 1; i <= X; i++){
for (int j = 1; j <= Y; j++){
if (area[i][j] == 1){
area2[M[i][j].first][M[i][j].second] = 1;
}
}
}
memset(match, -1, sizeof(match));
X = total_r, Y = total_c;
for (int i = 1; i <= X; i++){
memset(visit, 0, sizeof(visit));
if (dfs(i)) ans++;
}
cout << ans << endl;
}
};
int main(){
int C;
cin >> C;
Solve a;
while (C--){
a.Deal();
}
return 0;
}