题目链接:点击打开链接
题目大意:懒得说了
题目思路:看题目的的问法,我们很容易想到是最小点覆盖或者边覆盖的问题,我们可以发现对于某个重要的点(x,y),只用x,y其中一个点备选中就行,是不是发现了,就是最小点覆盖的定义:求最小数量的点,使得包括每条边的至少一个端点,所以,我们对于每一个重要位置的左边,根据行列建图,从x联向y,容量为1,然后求最小点覆盖,但是这里还有一个地方就是会有障碍点,那么我们可以先把每一行的坐标离散化,如果这一行有障碍,我们就加一,列的同理。。。
ac代码:
#include<cstdio>
#include<queue>
#include<iostream>
#include<sstream>
#include<map>
#include<cstring>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int inf = 0x3f3f3f3f;
const int MX = 200+5;
const int MXE = 5 * MX * MX;
int T;
int n,m;
int cnt1;
int cnt2;
int mp[105][105];
int r[105][105];
int c[105][105];
struct MaxFlow
{
struct Edge
{
int v, w, nxt;
} edge[MXE],edge2[MXE];
int tot, num, s, t;
int head[MX];
void init()
{
memset(head, -1, sizeof(head));
tot = 0;
}
void add(int u, int v, int w)
{
edge[tot].v = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
edge[tot].v = u;
edge[tot].w = 0;
edge[tot].nxt = head[v];
head[v] = tot++;
}
int d[MX], vis[MX], gap[MX];
void bfs()
{
memset(d, 0, sizeof(d));
memset(gap, 0, sizeof(gap));
memset(vis, 0, sizeof(vis));
queue<int>q;
q.push(t);
vis[t] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt)
{
int v = edge[i].v;
if (!vis[v])
{
d[v] = d[u] + 1;
gap[d[v]]++;
q.push(v);
vis[v] = 1;
}
}
}
}
int last[MX];
int dfs(int u, int f)
{
if (u == t) return f;
int sap = 0;
for (int i = last[u]; ~i; i = edge[i].nxt)
{
int v = edge[i].v;
if (edge[i].w > 0 && d[u] == d[v] + 1)
{
last[u] = i;
int tmp = dfs(v, min(f - sap, edge[i].w));
edge[i].w -= tmp;
edge[i ^ 1].w += tmp;
sap += tmp;
if (sap == f) return sap;
}
}
if (d[s] >= num) return sap;
if (!(--gap[d[u]])) d[s] = num;
++gap[++d[u]];
last[u] = head[u];
return sap;
}
int solve(int st, int ed, int n)
{
int flow = 0;
num = n;
s = st;
t = ed;
bfs();
memcpy(last, head, sizeof(head));
while (d[s] < num) flow += dfs(s, inf);
return flow;
}
} F;
int main()
{
scanf("%d",&T);
while(T--){
F.init();
memset(r,0,sizeof(r));
memset(c,0,sizeof(c));
memset(mp,0,sizeof(mp));
scanf("%d%d",&n,&m);
scanf("%d",&cnt1);
for(int i = 0;i<cnt1;i++){
int x,y;
scanf("%d%d",&x,&y);
mp[x][y] = 1;
}
scanf("%d",&cnt2);
for(int i = 0;i<cnt2;i++){
int x,y;
scanf("%d%d",&x,&y);
mp[x][y] = 2;
}
int N = 0;
for(int i = 1;i<=m;i++){
int ok = 1;
for(int j = 1;j<=n;j++){
if(mp[j][i]==1){
if(ok)
N++;
r[j][i] = N;
ok = 0;
}
else if(mp[j][i] == 2){
ok = 1;
}
}
}
int M = 0;
for(int i = 1;i<=n;i++){
int ok = 1;
for(int j = 1;j<=m;j++){
if(mp[i][j]==1){
if(ok)
M++;
c[i][j] = M+N;
ok = 0;
}
else if(mp[i][j]==2){
ok = 1;
}
}
}
for(int i = 1;i<=n;i++){
for(int j= 1;j<=m;j++){
if(mp[i][j] == 1){
F.add(r[i][j],c[i][j],1);
}
}
}
int NN = N;
int MM = M;
N = M = 0;
for(int i = 1;i<=m;i++){
int ok = 1;
for(int j = 1;j<=n;j++){
if(mp[j][i]==1){
if(ok){
N++;
F.add(NN+MM+1,N,1);
}
r[j][i] = N;
ok = 0;
}
else if(mp[j][i] == 2){
ok = 1;
}
}
}
for(int i = 1;i<=n;i++){
int ok = 1;
for(int j = 1;j<=m;j++){
if(mp[i][j]==1){
if(ok){
M++;
F.add(M+N,NN+MM+2,1);
}
c[i][j] = M+N;
ok = 0;
}
else if(mp[i][j]==2){
ok = 1;
}
}
}
//cout<<N<<' '<<M<<endl;
int ans = F.solve(NN+MM+1,NN+MM+2,NN+MM+2);
cout<<ans<<endl;
}
}