网络流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 }
View Code

 

 

 

第二题:太空飞行计划问题

最小割的应用,最大权闭合子图模板题,源点建正权,汇点建负权

最大权闭合子图的权值和 = 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 }
View Code

 

 

 

第三题:最小路径覆盖问题

最小路径覆盖,可看代码注释,拆点转化为二分图最大匹配

 

 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 }
View Code

 

posted @ 2020-12-08 20:49  不敢说的梦  阅读(127)  评论(0)    收藏  举报