网络流24题
网络流24题
洛谷题单:网络流24题
第一题:飞行员配对问题
二分图模板题,匈牙利可以过,并且匈牙利算法可以记录匹配的信息
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #define N 100010 6 using namespace std; 7 int cnt, n, m, head[N], nxt[N], to[N], p[N]; 8 bool vis[N]; 9 inline int read() { 10 int x = 0, y = 1; 11 char c = getchar(); 12 while (c < '0' || c > '9') { 13 if (c == '-') 14 y = -1; 15 c = getchar(); 16 } 17 while (c >= '0' && c <= '9') 18 x = x * 10 + c - '0', c = getchar(); 19 return x * y; 20 } 21 void add(int x, int y) { 22 nxt[++cnt] = head[x]; 23 head[x] = cnt; 24 to[cnt] = y; 25 } 26 bool match(int u) { 27 for (int i = head[u]; ~i; i = nxt[i]) { 28 int v = to[i]; 29 if (vis[v]) 30 continue; 31 else 32 vis[v] = true; 33 if (p[v] == 0 || match(p[v])) { 34 p[v] = u; 35 return true; 36 } 37 } 38 return false; 39 } 40 int pipei() { 41 int ans = 0; 42 for (int i = 1; i <= m; i++) { 43 memset(vis, false, sizeof(vis)); 44 if (match(i)) 45 ans++; 46 } 47 return ans; 48 } 49 int main() { 50 cnt = -1; 51 memset(head, -1, sizeof(head)); memset(p,0,sizeof(p)); 52 m = read(); 53 n = read(); 54 int u, v; 55 while (~scanf("%d%d", &u, &v) && u+v != -2) add(u, v); 56 int k = pipei(); 57 printf("%d\n",k); 58 for(int i = m+1; i <= n; i++) 59 if(p[i] != 0) 60 printf("%d %d\n",p[i],i); 61 return 0; 62 }
第二题:太空飞行计划问题
最小割的应用,最大权闭合子图模板题,源点建正权,汇点建负权
最大权闭合子图的权值和 = max{被选择的点权和} = 正点权和−min{没被选择的正权点之和 + 被选择的负权点绝对值和}
= 正点权和−最小割
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <vector> 6 #define N 10010 7 using namespace std; 8 vector<int> g[N]; 9 int cnt,n,m,s,t,head[N],nxt[N],to[N],d[N],cur[N],w[N],f[N]; 10 const int INF = 0x3f3f3f3f; 11 void add(int x, int y, int z) 12 { 13 nxt[++cnt] = head[x]; 14 head[x] = cnt; 15 to[cnt] = y; 16 w[cnt] = z; 17 } 18 bool bfs(int s, int t) 19 { 20 memset(d,-1,sizeof(d)); 21 d[s] = 0; 22 queue<int> q; 23 q.push(s); 24 while(!q.empty()) 25 { 26 int p = q.front(); q.pop(); 27 for(int i = head[p]; ~i; i = nxt[i]) 28 { 29 int v = to[i]; 30 if(d[v] == -1 && w[i]) 31 { 32 d[v] = d[p]+1; 33 q.push(v); 34 } 35 } 36 } 37 return d[t] != -1; 38 } 39 int dfs(int s, int flow) 40 { 41 if(s == t) return flow; 42 int ans = 0; 43 for(int i = cur[s]; ~i; i = nxt[i]) 44 { 45 int v = to[i]; 46 cur[s] = i; 47 if(d[v] == d[s]+1 && w[i]) 48 { 49 int dis = dfs(v,min(flow,w[i])); 50 if(dis) 51 { 52 w[i] -= dis; 53 w[i^1] += dis; 54 flow -= dis; 55 ans += dis; 56 if(flow == 0) break; 57 } 58 } 59 } 60 return ans; 61 } 62 int dinic(int s, int t) 63 { 64 int ans = 0; 65 while(bfs(s,t)) 66 { 67 memcpy(cur,head,sizeof(head)); 68 ans += dfs(s,INF); 69 } 70 return ans; 71 } 72 int main() 73 { 74 int sum = 0; 75 cnt = -1; memset(head,-1,sizeof(head)); 76 scanf("%d%d",&m,&n); 77 s = 0; t = n+m+1; 78 for(int i = 1; i <= m; i++) 79 { 80 int x; char c; 81 scanf("%d",&x); 82 sum += x; 83 add(s,i+n,x); add(i+n,s,0); 84 while(true) 85 { 86 scanf("%d%c",&x,&c); 87 add(i+n,x,INF); add(x,i+n,0); 88 if(c == '\n' || c == '\r') break; 89 } 90 } 91 for(int i = 1; i <= n; i++) 92 { 93 int x; 94 scanf("%d",&x); 95 add(i,t,x); add(t,i,0); 96 } 97 sum -= dinic(s,t); 98 for(int i = 1; i <= m; i++) 99 if(d[i+n] != -1) 100 printf("%d ",i); 101 puts(""); 102 for(int i = 1; i <= n; i++) 103 if(d[i] != -1) 104 printf("%d ",i); 105 puts(""); 106 printf("%d\n",sum); 107 return 0; 108 }
第三题:最小路径覆盖问题
最小路径覆盖,可看代码注释,拆点转化为二分图最大匹配
1 // 选出的路径最少 <=> 终点最少 <=> 二分图左侧的未匹配点最少 <=> 二分图匹配数最大 2 // 最少路径= 最少终点 = 总点数-最大匹配数 = n-maxflow 3 #include <iostream> 4 #include <cstdio> 5 #include <cstring> 6 #include <queue> 7 #define N 18010 8 using namespace std; 9 int cnt,n,m,head[N],nxt[N],to[N],p[N],p1[N]; 10 bool vis[N]; 11 inline int read() 12 { 13 int x = 0, y = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') y = -1; c = getchar();} while(c >= '0' && c <= '9') x = x*10+c-'0', c = getchar(); return x*y; 14 } 15 void add(int x, int y) 16 { 17 nxt[++cnt] = head[x]; 18 head[x] = cnt; 19 to[cnt] = y; 20 } 21 bool match(int u) 22 { 23 for(int i = head[u]; ~i; i = nxt[i]) 24 { 25 int v = to[i]; 26 if(vis[v]) continue; 27 else vis[v] = true; 28 if(p[v] == 0 || match(p[v])) 29 { 30 p[v] = u; 31 p1[u] = v; 32 return true; 33 } 34 } 35 return false; 36 } 37 int pipei() 38 { 39 int ans = 0; 40 for(int i = 1; i <= n; i++) 41 { 42 memset(vis,false,sizeof(vis)); 43 if(match(i)) 44 ans++; 45 } 46 return ans; 47 } 48 int main() 49 { 50 cnt = -1; memset(head,-1,sizeof(head)); 51 memset(p,0,sizeof(p)); memset(p1,0,sizeof(p1)); 52 n = read(); m = read(); 53 for(int i = 1; i <= m; i++) 54 { 55 int u,v; 56 u = read(); v = read(); 57 add(u,v+n); 58 } 59 int ans = n-pipei(); 60 for(int i = 0; i < ans; i++) 61 { 62 int j,pre; 63 vector<int> g; 64 for(j = 1; j <= n; j++) 65 { 66 if(p1[j] != 0) 67 { 68 g.push_back(j); 69 break; 70 } 71 } 72 while(p1[j] != 0) {pre = j; j = p1[j]-n; p1[pre] = 0; g.push_back(j);} 73 for(int k = 0; k < g.size(); k++) 74 printf("%d ",g[k]); 75 puts(""); 76 } 77 printf("%d",ans); 78 return 0; 79 }

浙公网安备 33010602011771号