POJ3041 Asteroids(最小點覆蓋)
阿新 • • 發佈:2018-12-16
啦啦啦
【題目分析】
比較經典的最小點覆蓋,對於障礙物(i,j),我們可以選擇消第i行,也可以選擇消第j列,所以所有障礙物橫縱座標連邊。
問最少消多少次,就是問最大能匹配幾次,轉化為最大匹配即可。
跑一遍網路流或匈牙利即可。
【程式碼~】
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> using namespace std; const int MAXN=1010; const int MAXM=2e4+10; const int INF=0x3f3f3f3f; int n,m,cnt,s,t; int head[MAXN],cur[MAXN],depth[MAXN]; int nxt[MAXM],to[MAXM],w[MAXM]; bool bfs() { queue<int> q; memset(depth,0,sizeof(depth)); depth[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=nxt[i]) { int v=to[i]; if(depth[v]==0&&w[i]) { depth[v]=depth[u]+1; q.push(v); } } } if(depth[t]==0) return false; return true; } int dfs(int u,int dist) { if(u==t) return dist; for(int &i=cur[u];i!=-1;i=nxt[i]) { int v=to[i]; if(depth[v]==depth[u]+1&&w[i]) { int di=dfs(v,min(w[i],dist)); if(di) { w[i]-=di; w[i^1]+=di; return di; } } } return 0; } int dinic() { int ans=0; while(bfs()) { for(int i=s;i<=t;++i) cur[i]=head[i]; while(int d=dfs(s,INF)) ans+=d; } return ans; } void Add(int x,int y,int z) { nxt[cnt]=head[x]; head[x]=cnt; to[cnt]=y; w[cnt]=z; cnt++; } void add(int x,int y,int z) { Add(x,y,z); Add(y,x,0); } int main() { memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); s=0,t=n+n+1; for(int i=1;i<=n;++i) add(s,i,1),add(i+n,t,1); for(int i=1;i<=m;++i) { int x,y; scanf("%d%d",&x,&y); add(x,y+n,1); } printf("%d\n",dinic()); return 0; }