先说做法:把原图拆成一个二分图,每一个点被拆成$A_i,B_i$,若原图中存在边$(u,v)$,则连边$(A_u,B_v)$,然后$S$对所有$A$连边,所有$B$对$T$连边,然后跑一个最大流求二分图的最大匹配,那么最小路径覆盖就就是点数减去最大匹配
证明:设一开始的时候每一条路径都只覆盖一个点,然后考虑如何把两条路径合起来。因为两条路径不能相交,所以在二分图上一条路径必定是增广路,而这一条增广路上的匹配数就是被合并的边数,也就是减少的路径数。所以只要求出最大匹配,再用一开始的$n$条路径减去最大匹配就行了
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<queue> 5 #include<cstring> 6 using namespace std; 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 8 char buf[1<<21],*p1=buf,*p2=buf; 9 inline int read(){ 10 #define num ch-'0' 11 char ch;bool flag=0;int res; 12 while(!isdigit(ch=getc())) 13 (ch=='-')&&(flag=true); 14 for(res=num;isdigit(ch=getc());res=res*10+num); 15 (flag)&&(res=-res); 16 #undef num 17 return res; 18 } 19 char sr[1<<21],z[20];int C=-1,Z; 20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 21 inline void print(int x){ 22 if(C>1<<20)Ot(); 23 while(z[++Z]=x%10+48,x/=10); 24 while(sr[++C]=z[Z],--Z); 25 } 26 const int N=505,M=50005,inf=0x3f3f3f3f; 27 int head[N],Next[M],ver[M],edge[M],cur[N],las[N],tot=1,vis[N]; 28 int n,m,s,t,dep[N]; 29 queue<int> q; 30 inline void add(int u,int v,int e){ 31 ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e; 32 ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=0; 33 } 34 bool bfs(){ 35 while(!q.empty()) q.pop(); 36 memset(dep,-1,sizeof(dep)); 37 for(int i=0;i<=2*n+1;++i) cur[i]=head[i]; 38 q.push(s),dep[s]=0; 39 while(!q.empty()){ 40 int u=q.front();q.pop(); 41 for(int i=head[u];i;i=Next[i]){ 42 int v=ver[i]; 43 if(dep[v]<0&&edge[i]){ 44 dep[v]=dep[u]+1,q.push(v); 45 if(v==t) return true; 46 } 47 } 48 } 49 return false; 50 } 51 int dfs(int u,int limit){ 52 if(!limit||u==t) return limit; 53 int flow=0,f; 54 for(int i=cur[u];i;i=Next[i]){ 55 int v=ver[i];cur[u]=i; 56 if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,edge[i])))){ 57 flow+=f,limit-=f; 58 edge[i]-=f,edge[i^1]+=f; 59 las[u]=v; 60 if(!limit) break; 61 } 62 } 63 return flow; 64 } 65 int dinic(){ 66 int flow=0; 67 while(bfs()) flow+=dfs(s,inf); 68 for(int i=1;i<=n;++i) 69 if(!vis[i]){ 70 int now=i; 71 print(now),sr[++C]=' '; 72 vis[now]=1; 73 while(las[now]){ 74 print(las[now]-n),sr[++C]=' '; 75 now=las[now]-n; 76 vis[now]=1; 77 } 78 sr[++C]=' '; 79 } 80 return flow; 81 } 82 int main(){ 83 n=read(),m=read(); 84 s=0,t=2*n+1; 85 for(int i=1;i<=n;++i) add(s,i,1),add(i+n,t,1); 86 for(int i=1;i<=m;++i){ 87 int u=read(),v=read(); 88 add(u,v+n,1); 89 } 90 print(n-dinic()),sr[++C]=' '; 91 Ot(); 92 return 0; 93 }