题目链接
比赛时一直以为是贪心题,结果一直被卡死, 只能说这应该是一道非常经典的二分图问题。
将每个点放在坐标轴上,即(t, pos+vt),而已知v为1,而在同一条斜率为1或-1的直线上的点可能都是同一个学生,所以这就转化成了非常经典的最小点覆盖问题,最少用多少条斜率固定线可以覆盖所有的点。
同时,我们可以把经过每个点的斜率为1和-1的直线与坐标轴的交点求出来,因为数据很大,记得离散化处理。因为最小点覆盖就等于二分图的最大匹配 (证明略) ,所以只要跑一遍匈牙利算法就ok了。
怕被卡时间,所以用了最大流优化了一下。
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 5e5 + 10;
vector<int> v1, v2;
struct edge {
int to, next, cap;
}e[N*2];
int T, n, m, cnt, h[N], maxflow, s, t;
int x[N], y[N], vis[N], match[N], dep[N], cur[N];
void add(int u, int v, int cap) {
e[cnt].to = v;
e[cnt].cap = cap;
e[cnt].next = h[u];
h[u] = cnt++;
e[cnt].to = u;
e[cnt].cap = 0;
e[cnt].next = h[v];
h[v] = cnt++;
}
bool bfs() {
for (int i = 0; i <= t; i++) dep[i] = -1, cur[i] = h[i];
queue<int> q;
q.push(s);
dep[s] = 0;
while (q.size()) {
int u = q.front();
q.pop();
for (int i = h[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (e[i].cap && dep[v] == -1) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
if (dep[t] >= 0) return true;
else return false;
}
int dfs(int u, int mx) {
int a;
if (u == t) return mx;
for (int i = cur[u]; ~i; i = e[i].next) {
cur[u] = i;
int v = e[i].to;
if (e[i].cap && dep[v] == dep[u] + 1 && (a = dfs(v, min(e[i].cap, mx)))) {
e[i].cap -= a;
e[i ^ 1].cap += a;
return a;
}
}
return 0;
}
void dinic() {
int res;
while (bfs()) {
while (1) {
res = dfs(s, INF);
if (!res) break;
maxflow += res;
}
}
}
void init() {
v1.clear();
v2.clear();
maxflow = 0;
cnt = 0;
}
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
init();
for (int i = 0; i < n; i++) {
int a, b;
scanf("%d %d", &a, &b);
x[i] = a + b, y[i] = a - b;
v1.push_back(x[i]), v2.push_back(y[i]);
}
sort(v1.begin(), v1.end());
v1.erase(unique(v1.begin(), v1.end()), v1.end());
sort(v2.begin(), v2.end());
v2.erase(unique(v2.begin(), v2.end()), v2.end());
int len = v1.size();
s = 0, t = v1.size() + v2.size() + 1;
for (int i = 0; i <= t; i++) h[i] = -1;
for (int i = 1; i <= len; i++) add(s, i, 1);
for (int i = 0; i < n; i++) {
y[i] = lower_bound(v2.begin(), v2.end(), y[i]) - v2.begin() + 1;
x[i] = lower_bound(v1.begin(), v1.end(), x[i]) - v1.begin() + 1;
add(x[i], y[i] + len, 1);
}
for (int i = len+1; i <= t-1; i++) add(i, t, 1);
dinic();
printf("%d\n", maxflow);
}
}