[BZOJ]1143: [CTSC2008]祭祀river
题目大意:给定一个n个点m条边的有向无环图,问最多选多少个点使得两两之间互不到达。(n<=100,m<=1000)
思路:题目所求即最长反链,最长反链=最小链覆盖,对每个点向自己能到的所有点连边后,转化成最小路径覆盖,每个点拆成入点和出点后二分图匹配,又有最大二分图匹配=最小路径覆盖,问题得到解决。复杂度O(nm+MaxFlow(n,n^2))。
#include<cstdio> #include<cstring> inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 100 #define MM 1000 #define MV 200 #define ME 10000 #define S MV+1 #define T MV+2 #define INF 0x7FFFFFFF namespace MaxFlow { struct edge{int nx,t,w;}e[ME*2+5]; int h[MV+5],en=1,d[MV+5],q[MV+5],qn,c[MV+5]; inline void ins(int x,int y,int w) { e[++en]=(edge){h[x],y,w};h[x]=en; e[++en]=(edge){h[y],x,0};h[y]=en; } bool bfs() { int i,j; memset(d,0,sizeof(d)); for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx) if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1; return d[T]; } int dfs(int x,int r) { if(x==T)return r; int k,u=0; for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+1) { k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w); u+=k;e[i].w-=k;e[i^1].w+=k; if(u==r)return r; } return d[x]=0,u; } int dinic(){int ans=0;while(bfs())ans+=dfs(S,INF);return ans;} }; struct edge{int nx,t;}e[MM+5]; int h[MN+5],en,q[MN+5],qn,u[MN+5]; inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;} int main() { int n,m,i,j,k,x,y; n=read();m=read(); while(m--)x=read(),y=read(),ins(x,y); using MaxFlow::ins; for(i=1;i<=n;++i) { ins(S,i,1);ins(i+n,T,1); memset(u,0,sizeof(u)); for(u[q[j=qn=0]=i]=1;j<=qn;++j)for(k=h[q[j]];k;k=e[k].nx) if(!u[e[k].t])ins(i,e[k].t+n,INF),u[q[++qn]=e[k].t]=1; } printf("%d",n-MaxFlow::dinic()); }