【网络流】——P2764 最小路径覆盖问题
一个最小路径覆盖的模板题。
Go:洛谷
- 最小路径覆盖=顶点数-二分图最大匹配
- 因此我们将点复制一份,按照题目给的数据在两端连边,长度为1。
- 建立一个super源&汇,源向左边的点连边,右边的点向汇连边,长度为1。
- 求解路径:
- 我们在邻接表中存下每条边的起始点,对于一条流为0的边,表示它是最小路径中的一条,那么用冰茶姬将他们连起来,最后访问单独集合中的路径即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 6e5+10,inf = 1e9; 4 int n, m, S, T, ans, d[N],head[N],maxflow,vis[N],f[N]; 5 int tot=-1; 6 struct edge{ 7 int w; 8 int next; 9 int to; 10 int from; 11 }e[N]; 12 int getf(int x){ 13 return f[x]==x?f[x]:f[x]=getf(f[x]); 14 } 15 inline void addedge(int x, int y, int z) { 16 e[++tot].to=y; 17 e[tot].next=head[x]; 18 e[tot].w=z; 19 e[tot].from=x; 20 head[x]=tot; 21 }//建图 22 int pos(int x,int y){ 23 return (x-1)*n+y; 24 } 25 inline bool bfs() { 26 memset(d, 0, sizeof(d)); 27 queue<int> q; 28 q.push(S); 29 d[S] = 1; 30 while (q.size()) { 31 int x = q.front(); 32 q.pop(); 33 for (int i = head[x]; i!=-1; i = e[i].next) { 34 int y = e[i].to, z = e[i].w; 35 if (d[y] || !z) continue; 36 q.push(y); 37 d[y] = d[x] + 1; 38 if (y == T) return 1; 39 } 40 } 41 return 0; 42 } 43 44 int dinic(int x, int flow) { 45 if (x == T) return flow; 46 int rest = flow; 47 for (int i = head[x]; i!=-1 && rest; i = e[i].next) { 48 int y = e[i].to, z = e[i].w; 49 if (d[y] != d[x] + 1 || !z) continue; 50 int k = dinic(y, min(rest, z)); 51 if (!k) d[y] = 0; 52 else { 53 e[i].w -= k; 54 e[i^1].w += k; 55 rest -= k; 56 } 57 } 58 return flow - rest; 59 } 60 void dfs2(int u){ 61 printf("%d ",u); 62 for(int i=head[u];i!=-1;i=e[i].next){ 63 if(e[i].w==0&&e[i].to>n) dfs2(e[i].to-n); 64 } 65 } 66 void solve(){ 67 int now=0; 68 while(bfs()){ 69 while(now=dinic(S,inf)) 70 maxflow+=now; 71 } 72 } 73 int main() { 74 memset(head,-1,sizeof(head)); 75 scanf("%d%d",&n,&m); 76 S=0,T=n*2+1; 77 int x,y; 78 for(int i=1;i<=m;i++){ 79 scanf("%d%d",&x,&y); 80 addedge(x,y+n,1); 81 addedge(y+n,x,0); 82 } 83 for(int i=1;i<=n;i++){ 84 addedge(S,i,1); 85 addedge(i,S,0); 86 addedge(n+i,T,1); 87 addedge(T,n+i,0); 88 } 89 solve(); 90 for(int i=1;i<=n;i++) f[i]=i; 91 for(int i=0;i<=tot;i++){ 92 if(e[i].from>=1&&e[i].from<=n&&e[i].to>n&&e[i].to<T&&!e[i].w) f[getf(e[i].to-n)]=getf(e[i].from); 93 } 94 for(int i=1;i<=n;i++){ 95 if(f[i]==i){ 96 dfs2(i); 97 printf("\n"); 98 } 99 } 100 printf("%d",n-maxflow); 101 return 0; 102 }
注:原来想用我的优化版dinic,但是不知道为啥跑不了,可能是我太弱了。
——抓住了时间,却不会利用的人,终究也逃不过失败的命运。