传送门biu~biu~
把每行建成一个点,每列建成一个点,如果有小行星(x,y)就连一条从x行到y列流量为1的弧。S连每行,流量为1;T连每列,流量为1。最小割即为最少次数。
(18/1/12UPD:最好理解成最小顶点覆盖问题)
#include<bits/stdc++.h>
using namespace std;
const int INF=1e9;
int n,k,S,T;
int dep[1005],fir[1005],head[1005],nex[50000],to[50000],cap[50000],tp=1;
inline void add(int x,int y,int c){
nex[++tp]=head[x];
head[x]=tp;
to[tp]=y;
cap[tp]=c;
}
inline int bfs(){
memset(dep,0,sizeof(dep));
dep[S]=1;queue<int>q;
q.push(S);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nex[i]){
if(cap[i] && !dep[to[i]]){
dep[to[i]]=dep[x]+1;
q.push(to[i]);
}
}
}
return dep[T];
}
int dfs(int x,int now){
if(x==T || !now) return now;
int c=0;
for(int &i=fir[x];i;i=nex[i]){
if(dep[to[i]]==dep[x]+1 && cap[i]){
int f=dfs(to[i],min(now,cap[i]));
now-=f;
cap[i]-=f;
cap[i^1]+=f;
c+=f;
if(!now) break;
}
}
return c;
}
inline int Dinic(){
int c=0;
while(bfs()){
for(int i=1;i<=2*n;++i) fir[i]=head[i];
fir[S]=head[S];fir[T]=head[T];
c+=dfs(S,INF);
}
return c;
}
int main(){
scanf("%d%d",&n,&k);S=2*n+1;T=2*n+2;
for(int i=1;i<=k;++i){
int x,y;
scanf("%d%d",&x,&y);
add(x,n+y,1); add(n+y,x,0);
}
for(int i=1;i<=n;++i) add(S,i,1),add(i,S,0);
for(int i=1;i<=n;++i) add(n+i,T,1),add(T,n+i,0);
printf("%d",Dinic());
return 0;
}