题意:一张DAG上找出一些点,使得它们不能相互到达,求最大点数。
也就是说,找DAG的最长反链,最长反链=n-最小链覆盖,拆点跑二分图最大匹配即可。
注意先用Floyd传递闭包。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN = 100005; const int INF=1<<30; struct Edge{ int nxt,to,f; }e[MAXN<<1]; int ecnt=1,head[MAXN],cur[MAXN]; inline void add(int x,int y,int f){ e[++ecnt].nxt = head[x]; e[ecnt].to = y; e[ecnt].f = f; head[x] = ecnt; } int dep[MAXN]; queue<int> Q; bool bfs(int S,int T){ memset(dep,0,sizeof(dep));dep[S]=1; Q.push(S); while(!Q.empty()){ int top=Q.front();Q.pop(); for(int i=head[top];i;i=e[i].nxt){ int v=e[i].to; if(dep[v]||!e[i].f)continue; dep[v]=dep[top]+1; Q.push(v); } } return dep[T]; } int dfs(int x,int flow,int T){ if(x==T)return flow; int used=0,tmp; for(int &i=cur[x];i;i=e[i].nxt){ int v=e[i].to; if(dep[v]!=dep[x]+1)continue; tmp=dfs(v,min(flow-used,e[i].f),T); e[i].f-=tmp;e[i^1].f+=tmp;used+=tmp; if(used==flow)return flow; } if(!used)dep[x]=-1; return used; } int dinic(int S,int T){ int ret=0; while(bfs(S,T)){memcpy(cur,head,sizeof(head));ret+=dfs(S,INF,T);} return ret; } int n,m; int a[105][105]; int main(){ n=rd();m=rd(); int x,y; for(int i=1;i<=m;i++){ x=rd();y=rd(); a[x][y]=1; } for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ a[i][j]|=a[i][k]&&a[k][j]; } } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(!a[i][j])continue; add(i,j+n,1);add(j+n,i,0); } } int S=n+n+1,T=S+1; for(int i=1;i<=n;i++){ add(S,i,1);add(i,S,0); add(i+n,T,1);add(T,i+n,0); } int ans=n-dinic(S,T); cout<<ans; return 0; }