2020杭電多校第四場 1007-Go Running dinic求二分圖最大匹配
阿新 • • 發佈:2020-08-05
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; }