-
Notifications
You must be signed in to change notification settings - Fork 126
/
UVa12549.cc
161 lines (145 loc) · 3.84 KB
/
UVa12549.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Sentry Robots, ACM/ICPC SWERC 2012, UVa12549
// 陈锋
#include <cassert>
#include <cctype>
#include <cstring>
#include <iostream>
#include <functional>
#include <algorithm>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <set>
#define _for(i,a,b) for( int i=(a); i<(b); ++i)
#define _rep(i,a,b) for( int i=(a); i<=(b); ++i)
using namespace std;
const int MAXX = 100+5;
// 二分图最大基数匹配
template<int maxn>
struct BPM {
int n, m; // 左右顶点个数
vector<int> G[maxn]; // 邻接表
int left[maxn]; // left[i]为右边第i个点的匹配点编号,-1表示不存在
bool T[maxn]; // T[i]为右边第i个点是否已标记
int right[maxn]; // 求最小覆盖用
bool S[maxn]; // 求最小覆盖用
void init(int n, int m) {
this->n = n;
this->m = m;
for(int i = 0; i < n; i++) G[i].clear();
}
void AddEdge(int u, int v) {
G[u].push_back(v);
}
bool match(int u){
S[u] = true;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if (!T[v]){
T[v] = true;
if (left[v] == -1 || match(left[v])){
left[v] = u;
right[u] = v;
return true;
}
}
}
return false;
}
// 求最大匹配
int solve() {
memset(left, -1, sizeof(left));
memset(right, -1, sizeof(right));
int ans = 0;
for(int u = 0; u < n; u++) { // 从左边结点u开始增广
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
if(match(u)) ans++;
}
return ans;
}
// 求最小覆盖。X和Y为最小覆盖中的点集
int mincover(vector<int>& X, vector<int>& Y) {
int ans = solve();
memset(S, 0, sizeof(S));
memset(T, 0, sizeof(T));
for(int u = 0; u < n; u++)
if(right[u] == -1) match(u); // 从所有X未盖点出发增广
for(int u = 0; u < n; u++)
if(!S[u]) X.push_back(u); // X中的未标记点
for(int v = 0; v < m; v++)
if(T[v]) Y.push_back(v); // Y中的已标记点
return ans;
}
};
struct Point {
int x, y;
Point(int x=0, int y=0):x(x),y(y) {}
char ch;
};
int Y, X, P, W;
vector<Point> points;
BPM<MAXX*MAXX*2> solver;
void dbgPrint() {
cout<<X<<"*"<<Y<<endl;
string line(X, '.');
vector<string> M(Y, line);
for(auto& p : points) {
// cout<<"p-> "<<p.y<<", "<<p.x<<endl;
assert(p.y < Y); assert(p.x < X);
M[p.y][p.x] = p.ch;
}
_for(i, 0, Y) cout<<M[i]<<endl;
}
int solve() {
sort(points.begin(), points.end(), [](const Point& p1, const Point& p2){
return p1.y < p2.y || (p1.y==p2.y && p1.x < p2.x); });
int dy = 0; // 垂直拆开
for(auto& p : points) {
bool isOb = (p.ch == '#');
if(isOb) dy++;
p.y += dy;
if(isOb) dy++;
}
Y += dy;
sort(points.begin(), points.end(), [](const Point& p1, const Point& p2){
return p1.x < p2.x || (p1.x==p2.x && p1.y < p2.y);});
int dx = 0; // 水平拆开
for(auto& p : points) {
bool isOb = (p.ch == '#');
if(isOb) dx++;
p.x += dx;
if(isOb) dx++;
}
X += dx;
solver.init(X, Y);
for(const auto& p : points)
if(p.ch == '*') solver.AddEdge(p.x, p.y);
vector<int> t1, t2;
solver.mincover(t1, t2);
return t1.size() + t2.size();
}
int main(){
int C; cin>>C;
_rep(t, 1, C){
cin>>Y>>X>>P;
points.clear();
Point p;
_for(i, 0, P){
cin>>p.y>>p.x;
p.ch = '*', p.x--, p.y--;
points.push_back(p);
}
cin>>W;
_for(i, 0, W) {
cin>>p.y>>p.x;
p.ch = '#', p.x--, p.y--;
points.push_back(p);
}
int ans = solve();
cout<<ans<<endl;
}
return 0;
}
// LiveArchive: 1473662 6156 Sentry Robots Accepted C++ 0.056 2014-06-27 07:22:02