最长反链=最小链覆盖
参考vfk dalao的博客:http://vfleaking.blog.163.com/blog/static/1748076342012918105514527/
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #include<string> #include<ctime> #include<queue> #include<map> #include<set> #include<vector> typedef long long LL; using namespace std; const int N=411,inf=1e9; int Write[20]; struct edge{int to,nxt,v;}e[48010]; int n,m,head[N],cnt,pre[N],ans,p[N],w[N],d[N],has[N],S,T; bool a[N][N]; int read() {int d=0,f=1; char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=(d<<3)+(d<<1)+c-48,c=getchar(); return d*f;} void write(int x){int t=0; for (;x;x/=10) Write[++t]=x%10; if (!t) putchar('0'); for (int i=t;i>=1;i--) putchar((char)(Write[i]+48));} void judge(){freopen(".in","r",stdin); freopen(".out","w",stdout);} void addedge(int x,int y,int z) { e[++cnt]=(edge){y,head[x],z}; head[x]=cnt; e[++cnt]=(edge){x,head[y],0}; head[y]=cnt; } void floyd() { 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]); } int sap() { int flow=inf,x=S,res=0; has[0]=T+1; for (int i=S;i<=T;i++) p[i]=head[i]; while (d[S]<T+1) { w[x]=flow; bool flag=0; for (int i=p[x];i;i=e[i].nxt) { int y=e[i].to; if (e[i].v==0||d[y]+1!=d[x]) continue; p[x]=i; flag=1; flow=min(flow,e[i].v); x=y; pre[x]=i; if (x==T) { res+=flow; while (x!=S) { int k=pre[x]; e[k].v-=flow; e[k^1].v+=flow; x=e[k^1].to; } flow=inf; } break; } if (flag) continue; int ljj,pjy=T; for (int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if (e[i].v&&d[y]<pjy) pjy=d[y],ljj=i; } if (--has[d[x]]==0) break; p[x]=ljj; has[d[x]=pjy+1]++; if (x!=S) x=e[pre[x]^1].to,flow=w[x]; } return res; } int main() { //judge(); n=read(); m=read(); S=0; T=2*n+1; for (int i=1;i<=m;i++) { int x=read(),y=read(); a[x][y]=1; } floyd(); cnt=1; for (int i=1;i<=n;i++) addedge(S,i,1),addedge(i+n,T,1); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (a[i][j]) addedge(i,j+n,inf); write(n-sap()); return 0; }