题解:最小路径覆盖=总点数减去最大匹配数,拆点,按照每条边前一个点连源点,后一个点连汇点跑最大流,即可跑出最大匹配数,然后减一减就可以了~
代码如下:
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define inf 0x3f3f3f3f #define hi puts("hi"); using namespace std; int head[100010],next[100010],v[100010],w[100010],deep[100010]; int s,t,cnt; void init() { cnt=-1; memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); } void add(int from,int to,int cost) { cnt++; next[cnt]=head[from]; w[cnt]=cost; v[cnt]=to; head[from]=cnt; } void add_edge(int from,int to,int cost) { add(from,to,cost); add(to,from,0); } int bfs(int s,int t) { queue<int> q; memset(deep,0,sizeof(deep)); deep[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1; i=next[i]) { if(w[i]>0&&(!deep[v[i]])) { deep[v[i]]=deep[u]+1; q.push(v[i]); // } } } if(!deep[t]) { return 0; } return 1; } int dfs(int u,int t,int dist) { if(u==t) { return dist; } for(int i=head[u]; i!=-1; i=next[i]) { if(w[i]&&(deep[v[i]]==deep[u]+1)) { int di=dfs(v[i],t,min(w[i],dist)); if(di>0) { w[i]-=di; w[i^1]+=di; return di; } } } return 0; } int dinic(int s,int t) { int res=0; while(bfs(s,t)) { while(int d=dfs(s,t,inf)) { res+=d; } } return res; } int n,m; int vis[100010]; int solve(int x,int &f) { int loc=x+n; vis[x]=1; for(int i=head[loc];i!=-1;i=next[i]) { if(w[i]==1&&v[i]!=n*2+1) { solve(v[i],f); } } if(f==1) { f=0; } else { putchar(' '); } printf("%d",x); } int main() { scanf("%d%d",&n,&m); init(); s=0;t=n*2+1; for(int i=1;i<=n;i++) { add_edge(s,i,1); add_edge(i+n,t,1); } int x,y; while(m--) { scanf("%d%d",&x,&y); add_edge(x,y+n,1); } int ans=n-dinic(s,t); for(int i=head[t];i!=-1;i=next[i]) { if(w[i]==1&&!vis[v[i]-n]) { int f=1; solve(v[i]-n,f); puts(""); } } printf("%d ",ans); }