2020杭电多校第四场 1007-Go Running dinic求二分图最大匹配
1007-Go Running
题意
给定平面上 \(n\) 个点,你可以选斜率为 \(1\) 与 \(−1\) 的直线去覆盖它,问最少要几条直线。
分析
对于平面上每个点有两条能覆盖它的直线,把这两条直线建点,这个点作为连接这两条直线的边,问题就转化为了二分图的最小点覆盖问题,二分图的最小点覆盖=二分图的最大匹配数,用\(dinic\)求二分图最大匹配可以在\(O(n\sqrt n)\)的时间复杂度解决。
Code
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<sstream>
#include<cstdio>
#include<string>
#include<vector>
#include<bitset>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,p<<1|1
#define pii pair<int,int>
#define lson l,mid,p<<1
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=2e5+10;
const int inf=1e9;
struct dinic{
struct ppo{
int v,c,next;
}e[N<<2];
int S,T,tot,h[N],d[N];
void init(){
S=0,T=1,tot=0;
memset(h,-1,sizeof(h));
}
void ae(int u,int v,int c){
e[tot]=ppo{v,c,h[u]};
h[u]=tot++;
}
void add(int u,int v,int c){
ae(u,v,c);
ae(v,u,0);
}
bool bfs(){
memset(d,-1,sizeof(d));
queue<int>q;
q.push(S);
d[S]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=h[u];~i;i=e[i].next){
int x=e[i].v,w=e[i].c;
if(d[x]==-1&&w){
d[x]=d[u]+1;
q.push(x);
}
}
}
return (d[T]!=-1);
}
int dfs(int u,int flow){
if(u==T) return flow;
int res=0;
for(int i=h[u];~i;i=e[i].next){
int x=e[i].v;
if(e[i].c&&d[u]+1==d[x]){
int tmp=dfs(x,min(flow,e[i].c));
flow-=tmp;
e[i].c-=tmp;
e[i^1].c+=tmp;
res+=tmp;
if(flow==0) break;
}
}
if(res==0) d[u]=-1;
return res;
}
int solve(){
int res=0;
while(bfs()){
res+=dfs(S,inf);
}
return res;
}
}dick;
int T,n,a[N],b[N],c[N];
vector<int>g[N];
int gao(int a[]){
rep(i,1,n) c[i]=a[i];
sort(c+1,c+n+1);
int tot=unique(c+1,c+n+1)-c-1;
int mx=0;
rep(i,1,n){
a[i]=lower_bound(c+1,c+tot+1,a[i])-c+1;
mx=max(a[i],mx);
}
return mx;
}
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d",&T);
while(T--){
dick.init();
scanf("%d",&n);
rep(i,1,n){
int t,x;
scanf("%d%d",&t,&x);
a[i]=t+x;
b[i]=t-x;
}
int n1=gao(a);
int n2=gao(b)+n1;
rep(i,1,n) b[i]+=n1;
rep(i,1,n){
g[0].pb(a[i]);
g[b[i]].pb(1);
g[a[i]].pb(b[i]);
}
rep(i,0,n2){
sort(g[i].begin(), g[i].end());
g[i].erase(unique(g[i].begin(), g[i].end()),g[i].end());
for(int x:g[i]){
dick.add(i,x,1);
}
g[i].clear();
}
printf("%d\n",dick.solve());
}
return 0;
}