网络流24题

骑士共存问题

按马的轨迹连边,最后是一张二分图,求最大匹配。可以跑匈牙利直接求出来,也可以连源点和汇点跑Dinic。

我是学二分图的时候写的,当时写的是匈牙利。我当时码风好奇怪

 1 #include <bits/stdc++.h>
 2 #define ID(x, y) (x - 1) * n + y
 3 #define New(p) p = &tmp[++ecnt]
 4 
 5 struct Edge {int to; Edge *nxt;} tmp[1000005], *head[40005];
 6 
 7 int vis[40005], match[40005], ecnt = -1, n, m, tim, ans, tot;
 8 int dx[] = {-1, -2, 1, 2, -1, -2, 1, 2}, dy[]={-2, -1, -2, -1, 2, 1, 2, 1};
 9 bool ban[205][205];
10 
11 inline void Add(int f, int to) {Edge *p; New(p); p -> to = to, p -> nxt = head[f], head[f] = p;}
12 
13 bool dfs(int x) {
14     for (Edge *i = head[x]; i != NULL; i = i -> nxt) {
15         if (vis[i -> to] != tim) {
16             vis[i -> to] = tim;
17             if (!match[i -> to] || dfs(match[i -> to])) {
18                 match[i -> to] = x;
19                 return 1;
20             }
21         }
22     }
23     return 0;
24 }
25 
26 signed main() {
27     scanf("%d%d", &n, &m);
28     for (int i = 1, x, y; i <= m; i++) {
29         scanf("%d%d", &x, &y);
30         ban[x][y] = 1;
31     }
32     for (int i = 1; i <= n; i++) {
33         for (int j = 1; j <= n; j++) {
34             if(ban[i][j] || ((i + j) & 1)) continue;
35             for (int k = 0; k < 8; k++) {
36                 int x = i + dx[k], y = j + dy[k];
37                 if (ban[x][y] || x < 1 || x > n || y < 1 || y > n) continue;
38                 Add(ID(i, j), ID(x, y));
39             }
40         }
41     }
42     for (int i = 1; i <= n; i++) {
43         for (int j = 1; j <= n; j++) {
44             if (!ban[i][j]) {
45                 ++tim;
46                 ++tot;
47                 if (dfs(ID(i, j))) ++ans;
48             }
49         }
50     }
51     printf("%d\n", tot - ans);
52     return 0;
53 }
匈牙利

飞行员配对方案问题

按给定关系建图,仍是二分图,求最大匹配。

依旧写的是匈牙利。我当时没看见SPJ,写了一堆奇怪的东西。。。。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 1005
 4 
 5 namespace Gekoo {
 6     struct Edge {
 7         int to, nxt;
 8     }e[N];
 9 
10     pair<int, int> p[N];
11 
12     int m, n, head[N], ecnt, match[N], ans, pcnt;
13     bool vis[N];
14 
15     void AddEdge(int f, int to) {
16         e[++ecnt].to = to;
17         e[ecnt].nxt = head[f];
18         head[f] = ecnt;
19     }
20 
21     bool dfs(int u) {
22         for (int i = head[u]; i; i = e[i].nxt) {
23             int v = e[i].to;
24             if (!vis[v]) {
25                 vis[v] = 1;
26                 if (!match[v] || dfs(match[v])) {
27                     match[v] = u;
28                     return 1;
29                 }
30             }
31         }
32         return 0;
33     }
34 
35     void QAQ() {
36         scanf("%d%d", &m, &n);
37         int i, j;
38         while (1) {
39             scanf("%d%d", &i, &j);
40             if (i == -1 && j == -1) break;
41             else AddEdge(i, j);
42         }
43         for (int i = 1; i <= m; i++) {
44             memset(vis, 0, sizeof(vis));
45             if(dfs(i)) ans++;
46         }
47         if (ans == 0) {
48             puts("No Solution!");
49             return ;
50         } else {
51             printf("%d\n", ans);
52             for (int i = m + 1; i <= n; i++) {
53                 if (match[i]) {
54                     p[++pcnt] = make_pair(match[i], i);
55                 }
56             }
57             sort(p + 1, p + 1 + pcnt);
58             for (int i = 1; i <= pcnt; i++) {
59                 printf("%d %d\n", p[i].first, p[i].second);
60             }
61             return ;
62         }
63     }
64 }
65 
66 signed main() {
67     Gekoo::QAQ();
68     return 0;
69 }
又是匈牙利

方格取数问题

把图按格子奇偶性黑白染色,源点连黑色,白色连汇点,黑色向相邻白点连,求出最小割,用数字和减去。

建出来的仍是二分图,这个过程其实就是在求二分图的最大独立集。

 1 #include <bits/stdc++.h>
 2 #define id(x, y) ((x - 1) * m + y) 
 3 
 4 const int N = 500005, INF = 0x3f3f3f3f;
 5 const int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};
 6 int n, m, sum, ecnt = 1, S, T;
 7 int matrix[105][105], head[N], dep[N];
 8 struct Edge {
 9     int to, nxt, val;
10 } e[N << 5];
11 
12 inline void addEdge(int f, int to, int val) {
13     e[++ecnt] = {to, head[f], val}, head[f] = ecnt;
14     e[++ecnt] = {f, head[to], 0}, head[to] = ecnt;
15 }
16 
17 bool bfs() {
18     memset(dep, 0, sizeof(dep));
19     dep[S] = 1;
20     std::queue<int> q;
21     q.push(S);
22     while (!q.empty()) {
23         int x = q.front();
24         q.pop();
25         for (int i = head[x], y = e[i].to; i; i = e[i].nxt, y = e[i].to) {
26             if (!dep[y] && e[i].val) {
27                 dep[y] = dep[x] + 1;
28                 if (y == T) return true;
29                 q.push(y);
30             }
31         }
32     }
33     return false;
34 }
35 
36 int dfs(int x, int flow) {
37     if (x == T) return flow;
38     int las = flow, q;
39     for (int i = head[x], y = e[i].to; i; i = e[i].nxt, y = e[i].to) {
40         if (dep[y] == dep[x] + 1 && e[i].val && las) {
41             q = dfs(y, std::min(e[i].val, las));
42             if (!q) {dep[y] = 0; continue;}
43             las -= q, e[i].val -= q, e[i^1].val += q;
44         }
45     }
46     return flow - las;
47 }
48 
49 int dinic() {
50     int maxflow = 0;
51     while (bfs()) maxflow += dfs(S, INF);
52     return maxflow;
53 }
54 
55 signed main() {
56     scanf("%d%d", &n, &m);
57     for (int i = 1; i <= n; i++) {
58         for (int j = 1; j <= m; j++) {
59             scanf("%d", &matrix[i][j]);
60             sum += matrix[i][j];
61         }
62     }
63     S = n * m  + 1, T = S + 1;
64     for (int i = 1; i <= n; i++) {
65         for (int j = 1; j <= m; j++) {
66             if ((i + j) & 1) {
67                 addEdge(S, id(i, j), matrix[i][j]);
68                 for (int k = 0; k <= 3; k++) {
69                     int xx = i + dx[k], yy = j + dy[k];
70                     if (xx < 1 || yy < 1 || xx > n || yy > m) continue;
71                     addEdge(id(i, j), id(xx, yy), INF);
72                 }
73             } else {
74                 addEdge(id(i, j), T, matrix[i][j]);
75             }
76         }
77     }
78     printf("%d\n", sum - dinic());
79     return 0;
80 }
这次是Dinic了

 

posted @ 2019-08-12 21:15  Gekoo  阅读(178)  评论(0编辑  收藏  举报