【线性规划和网络流24题】

(1)飞行员配对方案问题:二分图最大匹配。

思路:略。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #define MAXN 1010
 4 int cx[MAXN], cy[MAXN];
 5 int first[MAXN], next[MAXN], v[MAXN], e;
 6 bool vis[MAXN];
 7 inline void addEdge(int x, int y) {
 8     v[e] = y;
 9     next[e] = first[x];
10     first[x] = e++;
11 }
12 int path(int x) {
13     int i;
14     int y;
15     for (i = first[x]; i != -1; i = next[i]) {
16         y = v[i];
17         if (!vis[y]) {
18             vis[y] = true;
19             if (cy[y] == -1 || path(cy[y])) {
20                 cx[x] = y;
21                 cy[y] = x;
22                 return 1;
23             }
24         }
25     }
26     return 0;
27 }
28 int main() {
29     int n, m;
30     int i;
31     int x, y;
32     int ans;
33     while (~scanf("%d%d", &m, &n)) {
34         e = 0;
35         memset(first, -1, sizeof(first));
36         while (scanf("%d%d", &x, &y), x != -1) {
37             addEdge(x, y);
38         }
39         ans = 0;
40         memset(cx, -1, sizeof(cx));
41         memset(cy, -1, sizeof(cy));
42         for (i = 1; i <= m; i++) {
43             memset(vis, false, sizeof(vis));
44             ans += path(i);
45         }
46         if (ans) {
47             printf("%d\n", ans);
48             for (i = 1; i <= m; i++) {
49                 if (cx[i] != -1) {
50                     printf("%d %d\n", i, cx[i]);
51                 }
52             }
53         } else {
54             puts("No Solution!");
55         }
56     }
57     return 0;
58 }

(2)太空飞行计划问题:最大权闭合图。

思路:

1。源向实验连边,流量为收益。

2。仪器向汇连边,流量为消耗。

3。实验向仪器连边,流量为无穷。

4。所有实验的收益-最大流=最大收益。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<algorithm>
  5 #include<iostream>
  6 #define MAXL 1010
  7 #define MAXN 100010
  8 #define MAXM 1000010
  9 #define oo 0x7FFFFFFF
 10 using namespace std;
 11 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
 12 int n;
 13 int src, des;
 14 
 15 bool flag;
 16 bool vis[MAXL];
 17 char str[MAXN];
 18 vector<int> g[MAXL];
 19 vector<int> test;
 20 vector<int> app;
 21 int a[MAXL];
 22 inline void addEdge(int x, int y, int val) {
 23     v[e] = y;
 24     cost[e] = val;
 25     next[e] = first[x];
 26     first[x] = e++;
 27 
 28     v[e] = x;
 29     cost[e] = 0;
 30     next[e] = first[y];
 31     first[y] = e++;
 32 }
 33 int SAP() {
 34     int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
 35     int flow = 0;
 36     int aug = oo;
 37     int x, y;
 38     bool flag;
 39     for (int i = 0; i < n; i++) {
 40         cur[i] = first[i];
 41         gap[i] = dis[i] = 0;
 42     }
 43     gap[src] = n;
 44     x = pre[src] = src;
 45     while (dis[src] < n) {
 46         flag = false;
 47         for (int &j = cur[x]; j != -1; j = next[j]) {
 48             y = v[j];
 49             if (cost[j] > 0 && dis[x] == dis[y] + 1) {
 50                 flag = true;
 51                 aug = min(aug, cost[j]);
 52                 pre[y] = x;
 53                 x = y;
 54                 if (x == des) {
 55                     flow += aug;
 56                     while (x != src) {
 57                         x = pre[x];
 58                         cost[cur[x]] -= aug;
 59                         cost[cur[x] ^ 1] += aug;
 60                     }
 61                     aug = oo;
 62                 }
 63                 break;
 64             }
 65         }
 66         if (flag) {
 67             continue;
 68         }
 69         int tmp = n;
 70         for (int j = first[x]; j != -1; j = next[j]) {
 71             y = v[j];
 72             if (cost[j] > 0 && dis[y] < tmp) {
 73                 tmp = dis[y];
 74                 cur[x] = j;
 75             }
 76         }
 77         if ((--gap[dis[x]]) == 0) {
 78             break;
 79         }
 80         gap[dis[x] = tmp + 1]++;
 81         x = pre[x];
 82     }
 83     return flow;
 84 }
 85 void out(vector<int> res) {
 86     int i;
 87     sort(res.begin(), res.end());
 88     res.resize(unique(res.begin(), res.end()) - res.begin());
 89     for (i = 0; i < (int) res.size(); i++) {
 90         if (i) {
 91             putchar(' ');
 92         }
 93         printf("%d", res[i]);
 94     }
 95     putchar('\n');
 96 }
 97 void dfs(int x) {
 98     int i;
 99     vis[x] = true;
100     if (x == des) {
101         flag = false;
102     }
103     for (i = first[x]; i != -1; i = next[i]) {
104         if (!vis[v[i]] && cost[i] > 0) {
105             dfs(v[i]);
106         }
107     }
108 }
109 int main() {
110     int m;
111     int i, j, k;
112     int len;
113     int ans;
114     while (~scanf("%d%d", &m, &n)) {
115         src = 0;
116         des = n + m + 1;
117         e = 0;
118         memset(first, -1, sizeof(first));
119         gets(str);
120         for (i = 1; i <= m; i++) {
121             g[i].clear();
122             gets(str);
123             len = strlen(str);
124             for (j = 0; j < len; j++) {
125                 for (; j < len && str[j] == ' '; j++)
126                     ;
127                 if (j < len) {
128                     sscanf(str + j, "%d", &k);
129                     g[i].push_back(k);
130                 }
131                 for (; j < len && isdigit(str[j]); j++)
132                     ;
133             }
134         }
135         for (i = 1; i <= n; i++) {
136             scanf("%d", &a[i]);
137             addEdge(m + i, des, a[i]);
138         }
139         ans = 0;
140         for (i = 1; i <= m; i++) {
141             addEdge(src, i, g[i][0]);
142             ans += g[i][0];
143             for (j = 1; j < (int) g[i].size(); j++) {
144                 addEdge(i, m + g[i][j], oo);
145             }
146         }
147         n = des + 1;
148         ans -= SAP();
149         test.clear();
150         app.clear();
151         for (i = first[src]; i != -1; i = next[i]) {
152             k = v[i];
153             flag = true;
154             memset(vis, false, sizeof(vis));
155             dfs(k);
156             if (flag) {
157                 test.push_back(k);
158                 for (j = 1; j < (int) g[k].size(); j++) {
159                     app.push_back(g[k][j]);
160                 }
161             }
162         }
163         out(test);
164         out(app);
165         printf("%d\n", ans);
166     }
167     return 0;
168 }

 (3)最小路径覆盖问题:有向无环图最小路径覆盖。

思路:

1。当原图没有边,增加一条边,就增加一个匹配,显然少了一条路径。

2。当已经有了一个匹配,增加一条边,不会增加匹配数,路径数需增加1。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #define MAXN 1010
 5 #define MAXM 100010
 6 using namespace std;
 7 int first[MAXN], v[MAXM], next[MAXM], e;
 8 int cx[MAXN], cy[MAXN];
 9 bool vis[MAXN];
10 vector<int> res;
11 inline void addEdge(int x, int y) {
12     next[e] = first[x];
13     v[e] = y;
14     first[x] = e++;
15 }
16 int path(int x) {
17     int i;
18     int y;
19     for (i = first[x]; i != -1; i = next[i]) {
20         y = v[i];
21         if (!vis[y]) {
22             vis[y] = true;
23             if (cy[y] == -1 || path(cy[y])) {
24                 cx[x] = y;
25                 cy[y] = x;
26                 return 1;
27             }
28         }
29     }
30     return 0;
31 }
32 int Match(int n) {
33     int i;
34     int ans = 0;
35     memset(cx, -1, sizeof(cx));
36     memset(cy, -1, sizeof(cy));
37     for (i = 1; i <= n; i++) {
38         memset(vis, false, sizeof(vis));
39         ans += path(i);
40     }
41     return n - ans;
42 }
43 void dfs(int x) {
44     vis[x] = true;
45     res.push_back(x);
46     if (cx[x] != -1) {
47         dfs(cx[x]);
48     }
49 }
50 int main() {
51     int n, m;
52     int i, j;
53     int x, y;
54     int ans;
55     while (~scanf("%d%d", &n, &m)) {
56         e = 0;
57         memset(first, -1, sizeof(first));
58         for (i = 0; i < m; i++) {
59             scanf("%d%d", &x, &y);
60             addEdge(x, y);
61         }
62         ans = Match(n);
63         memset(vis, false, sizeof(vis));
64         for (i = 1; i <= n; i++) {
65             if (!vis[i]) {
66                 res.clear();
67                 dfs(i);
68                 for (j = 0; j < (int) res.size() - 1; j++) {
69                     printf("%d ", res[j]);
70                 }
71                 printf("%d\n", res[j]);
72             }
73         }
74         printf("%d\n", ans);
75     }
76     return 0;
77 }

(4)魔术球问题:有向无环图最小路径覆盖。

思路:

1。若x+y为平方数,则x,y'连一条有向边。

2。递增答案,同时增加新的边,更新二分图的交错路。

3。最小路径覆盖=顶点数-二分图最大匹配。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #define MAXN 2010
 5 #define MAXM 200010
 6 using namespace std;
 7 int first[MAXN], next[MAXM], v[MAXM], e;
 8 int cx[MAXN], cy[MAXN];
 9 int nx[MAXN];
10 bool vis[MAXN];
11 bool sqr[MAXM];
12 vector<int> res;
13 void init() {
14     int i;
15     memset(sqr, false, sizeof(sqr));
16     for (i = 1; i * i < MAXM; i++) {
17         sqr[i * i] = true;
18     }
19 }
20 inline void addEdge(int x, int y) {
21     v[e] = y;
22     next[e] = first[x];
23     first[x] = e++;
24 }
25 int path(int x) {
26     int i;
27     int y;
28     for (i = first[x]; i != -1; i = next[i]) {
29         y = v[i];
30         if (!vis[y]) {
31             vis[y] = true;
32             if (cy[y] == -1 || path(cy[y])) {
33                 cx[x] = y;
34                 cy[y] = x;
35                 return 1;
36             }
37         }
38     }
39     return 0;
40 }
41 int cal(int n) {
42     int i;
43     int ans;
44     for (i = 1; i < n; i++) {
45         if (sqr[i + n]) {
46             addEdge(i, n);
47         }
48     }
49     ans = 0;
50     for (i = 1; i <= n; i++) {
51         if (cx[i] == -1) {
52             memset(vis, false, sizeof(vis));
53             ans += path(i);
54         } else {
55             ans++;
56         }
57     }
58     return n - ans;
59 }
60 void dfs(int x) {
61     vis[x] = true;
62     res.push_back(x);
63     if (nx[x] != -1) {
64         dfs(nx[x]);
65     }
66 }
67 int main() {
68     int n;
69     int i, j;
70     init();
71     while (~scanf("%d", &n)) {
72         e = 0;
73         memset(first, -1, sizeof(first));
74         memset(cx, -1, sizeof(cx));
75         memset(cy, -1, sizeof(cy));
76         for (i = 1; cal(i) <= n; i++) {
77             memcpy(nx, cx, sizeof(nx));
78         }
79         n = i - 1;
80         printf("%d\n", n);
81         memset(vis, false, sizeof(vis));
82         for (i = 1; i <= n; i++) {
83             if (!vis[i]) {
84                 res.clear();
85                 dfs(i);
86                 for (j = 0; j < (int) res.size() - 1; j++) {
87                     printf("%d ", res[j]);
88                 }
89                 printf("%d\n", res[j]);
90             }
91         }
92     }
93     return 0;
94 }

(5)圆桌问题:二分图多重匹配。

思路:

1。从源点向每个单位连边,流量为单位人数。

2。从每个圆桌向汇点连边,流量为圆桌人数。

3。每个单位向每个圆桌都连边,流量为1。

4。求最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #define MAXN 1010
  5 #define MAXM 1000010
  6 #define oo 0x7FFFFFFF
  7 using namespace std;
  8 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
  9 int n;
 10 int src, des;
 11 inline void addEdge(int x, int y, int val) {
 12     v[e] = y;
 13     cost[e] = val;
 14     next[e] = first[x];
 15     first[x] = e++;
 16 
 17     v[e] = x;
 18     cost[e] = 0;
 19     next[e] = first[y];
 20     first[y] = e++;
 21 }
 22 int SAP() {
 23     int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
 24     int flow = 0;
 25     int aug = oo;
 26     int x, y;
 27     bool flag;
 28     for (int i = 0; i < n; i++) {
 29         cur[i] = first[i];
 30         gap[i] = dis[i] = 0;
 31     }
 32     gap[src] = n;
 33     x = pre[src] = src;
 34     while (dis[src] < n) {
 35         flag = false;
 36         for (int &j = cur[x]; j != -1; j = next[j]) {
 37             y = v[j];
 38             if (cost[j] > 0 && dis[x] == dis[y] + 1) {
 39                 flag = true;
 40                 aug = min(aug, cost[j]);
 41                 pre[y] = x;
 42                 x = y;
 43                 if (x == des) {
 44                     flow += aug;
 45                     while (x != src) {
 46                         x = pre[x];
 47                         cost[cur[x]] -= aug;
 48                         cost[cur[x] ^ 1] += aug;
 49                     }
 50                     aug = oo;
 51                 }
 52                 break;
 53             }
 54         }
 55         if (flag) {
 56             continue;
 57         }
 58         int tmp = n;
 59         for (int j = first[x]; j != -1; j = next[j]) {
 60             y = v[j];
 61             if (cost[j] > 0 && dis[y] < tmp) {
 62                 tmp = dis[y];
 63                 cur[x] = j;
 64             }
 65         }
 66         if ((--gap[dis[x]]) == 0) {
 67             break;
 68         }
 69         gap[dis[x] = tmp + 1]++;
 70         x = pre[x];
 71     }
 72     return flow;
 73 }
 74 int main() {
 75     int m;
 76     int i, j;
 77     int tot;
 78     vector<int> res[MAXN];
 79     scanf("%d%d", &m, &n);
 80     src = 0;
 81     des = n + m + 1;
 82     e = 0;
 83     memset(first, -1, sizeof(first));
 84     tot = 0;
 85     for (i = 1; i <= m; i++) {
 86         scanf("%d", &j);
 87         addEdge(src, i, j);
 88         tot += j;
 89     }
 90     for (i = 1; i <= n; i++) {
 91         scanf("%d", &j);
 92         addEdge(m + i, des, j);
 93     }
 94     for (i = 1; i <= m; i++) {
 95         for (j = m + 1; j <= n + m; j++) {
 96             addEdge(i, j, 1);
 97         }
 98     }
 99     n = des + 1;
100     for (i = 0; i < MAXN; i++) {
101         res[i].clear();
102     }
103     if (tot == SAP()) {
104         puts("1");
105         for (i = first[src]; i != -1; i = next[i]) {
106             for (j = first[v[i]]; j != -1; j = next[j]) {
107                 if (cost[j] == 0) {
108                     res[v[i]].push_back(v[j] - m);
109                 }
110             }
111         }
112         for (i = 1; i <= m; i++) {
113             for (j = 0; j < (int) res[i].size() - 1; j++) {
114                 printf("%d ", res[i][j]);
115             }
116             printf("%d\n", res[i][j]);
117         }
118     } else {
119         puts("0");
120     }
121     return 0;
122 }

(6)最长递增子序列问题:最多不相交路径。

思路:

1。对于第一问:dp即可。

2。每个点取的次数有要求,所以需要拆点,限制流量。

3。控制最长递增子序列,要从dp转移来连边。

 题目描述有错:应是最长非降子序列,而不是严格递增的。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #define MAXN 10010
  5 #define MAXM 1000010
  6 #define oo 123456789
  7 using namespace std;
  8 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
  9 int n;
 10 int src, des;
 11 
 12 int dp[MAXN];
 13 int arr[MAXN];
 14 inline void addEdge(int x, int y, int val) {
 15     v[e] = y;
 16     cost[e] = val;
 17     next[e] = first[x];
 18     first[x] = e++;
 19 
 20     v[e] = x;
 21     cost[e] = 0;
 22     next[e] = first[y];
 23     first[y] = e++;
 24 }
 25 int SAP() {
 26     int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
 27     int flow = 0;
 28     int aug = oo;
 29     int x, y;
 30     bool flag;
 31     for (int i = 0; i < n; i++) {
 32         cur[i] = first[i];
 33         gap[i] = dis[i] = 0;
 34     }
 35     gap[src] = n;
 36     x = pre[src] = src;
 37     while (dis[src] < n) {
 38         flag = false;
 39         for (int &j = cur[x]; j != -1; j = next[j]) {
 40             y = v[j];
 41             if (cost[j] > 0 && dis[x] == dis[y] + 1) {
 42                 flag = true;
 43                 aug = min(aug, cost[j]);
 44                 pre[y] = x;
 45                 x = y;
 46                 if (x == des) {
 47                     flow = min(flow + aug, oo);
 48                     while (x != src) {
 49                         x = pre[x];
 50                         cost[cur[x]] -= aug;
 51                         cost[cur[x] ^ 1] += aug;
 52                     }
 53                     aug = oo;
 54                 }
 55                 break;
 56             }
 57         }
 58         if (flag) {
 59             continue;
 60         }
 61         int tmp = n;
 62         for (int j = first[x]; j != -1; j = next[j]) {
 63             y = v[j];
 64             if (cost[j] > 0 && dis[y] < tmp) {
 65                 tmp = dis[y];
 66                 cur[x] = j;
 67             }
 68         }
 69         if ((--gap[dis[x]]) == 0) {
 70             break;
 71         }
 72         gap[dis[x] = tmp + 1]++;
 73         x = pre[x];
 74     }
 75     return flow;
 76 }
 77 int getIndex(int x) {
 78     return 2 * x - 1;
 79 }
 80 void cal(int len, int val) {
 81     int i, j;
 82     int tmp;
 83     int ans;
 84     e = 0;
 85     memset(first, -1, sizeof(first));
 86     src = 0;
 87     des = 2 * n + 1;
 88     for (i = 1; i <= n; i++) {
 89         if (i == 1 || i == n) {
 90             addEdge(getIndex(i), getIndex(i) + 1, val);
 91         } else {
 92             addEdge(getIndex(i), getIndex(i) + 1, 1);
 93         }
 94     }
 95     for (i = 1; i <= n; i++) {
 96         if (dp[i] == 1) {
 97             addEdge(src, getIndex(i), oo);
 98         }
 99         if (dp[i] == len) {
100             addEdge(getIndex(i) + 1, des, oo);
101         }
102     }
103     for (i = 1; i <= n; i++) {
104         for (j = 1; j < i; j++) {
105             if (arr[i] >= arr[j] && dp[i] == dp[j] + 1) {
106                 addEdge(getIndex(j) + 1, getIndex(i), 1);
107             }
108         }
109     }
110     tmp = n;
111     n = des + 1;
112     ans = SAP();
113     n = tmp;
114     if (ans == oo) {
115         ans = n;
116     }
117     printf("%d\n", ans);
118 }
119 int main() {
120     int i, j;
121     int ans;
122     while (~scanf("%d", &n)) {
123         for (i = 1; i <= n; i++) {
124             scanf("%d", &arr[i]);
125             dp[i] = 1;
126         }
127         for (i = 1; i <= n; i++) {
128             for (j = 1; j < i; j++) {
129                 if (arr[i] >= arr[j]) {
130                     dp[i] = max(dp[i], dp[j] + 1);
131                 }
132             }
133         }
134         ans = 0;
135         for (i = 1; i <= n; i++) {
136             ans = max(ans, dp[i]);
137         }
138         printf("%d\n", ans);
139         cal(ans, 1);
140         cal(ans, oo);
141     }
142     return 0;
143 }

(7)试题库问题:二分图多重匹配。

思路:

1。从源点向每道试题连边,流量为1。

2。从每个类型向汇点连边,流量为每个类型所需要的题数。

3。每个试题向所属的类型都连边,流量为1。

4。求最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #define MAXN 1010
  5 #define MAXM 1000010
  6 #define oo 0x7FFFFFFF
  7 using namespace std;
  8 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
  9 int n;
 10 int src, des;
 11 inline void addEdge(int x, int y, int val) {
 12     v[e] = y;
 13     cost[e] = val;
 14     next[e] = first[x];
 15     first[x] = e++;
 16 
 17     v[e] = x;
 18     cost[e] = 0;
 19     next[e] = first[y];
 20     first[y] = e++;
 21 }
 22 int SAP() {
 23     int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
 24     int flow = 0;
 25     int aug = oo;
 26     int x, y;
 27     bool flag;
 28     for (int i = 0; i < n; i++) {
 29         cur[i] = first[i];
 30         gap[i] = dis[i] = 0;
 31     }
 32     gap[src] = n;
 33     x = pre[src] = src;
 34     while (dis[src] < n) {
 35         flag = false;
 36         for (int &j = cur[x]; j != -1; j = next[j]) {
 37             y = v[j];
 38             if (cost[j] > 0 && dis[x] == dis[y] + 1) {
 39                 flag = true;
 40                 aug = min(aug, cost[j]);
 41                 pre[y] = x;
 42                 x = y;
 43                 if (x == des) {
 44                     flow += aug;
 45                     while (x != src) {
 46                         x = pre[x];
 47                         cost[cur[x]] -= aug;
 48                         cost[cur[x] ^ 1] += aug;
 49                     }
 50                     aug = oo;
 51                 }
 52                 break;
 53             }
 54         }
 55         if (flag) {
 56             continue;
 57         }
 58         int tmp = n;
 59         for (int j = first[x]; j != -1; j = next[j]) {
 60             y = v[j];
 61             if (cost[j] > 0 && dis[y] < tmp) {
 62                 tmp = dis[y];
 63                 cur[x] = j;
 64             }
 65         }
 66         if ((--gap[dis[x]]) == 0) {
 67             break;
 68         }
 69         gap[dis[x] = tmp + 1]++;
 70         x = pre[x];
 71     }
 72     return flow;
 73 }
 74 int main() {
 75     int m;
 76     int i, j, k;
 77     int tot;
 78     vector<int> res[MAXN];
 79     while (~scanf("%d%d", &m, &n)) {
 80         tot = 0;
 81         src = 0;
 82         des = m + n + 1;
 83         e = 0;
 84         memset(first, -1, sizeof(first));
 85         for (i = 1; i <= m; i++) {
 86             scanf("%d", &j);
 87             addEdge(n + i, des, j);
 88             tot += j;
 89         }
 90         for (i = 1; i <= n; i++) {
 91             scanf("%d", &j);
 92             addEdge(src, i, 1);
 93             while (j--) {
 94                 scanf("%d", &k);
 95                 addEdge(i, n + k, 1);
 96             }
 97         }
 98         k = n;
 99         n = des + 1;
100         if (SAP() == tot) {
101             for (i = 0; i < MAXN; i++) {
102                 res[i].clear();
103             }
104             for (i = first[src]; i != -1; i = next[i]) {
105                 for (j = first[v[i]]; j != -1; j = next[j]) {
106                     if (cost[j] == 0) {
107                         if (v[j] > k)
108                             res[v[j] - k].push_back(v[i]);
109                     }
110                 }
111             }
112             for (i = 1; i <= m; i++) {
113                 printf("%d:", i);
114                 for (j = 0; j < (int) res[i].size(); j++) {
115                     printf(" %d", res[i][j]);
116                 }
117                 putchar('\n');
118             }
119         } else {
120             puts("No Solution!");
121         }
122     }
123     return 0;
124 }

(9)方格取数问题:二分图点权最大独立集。

思路:

1。方格黑白染色。源向黑格连边,流量为点权;白格向汇连边,流量为点权;黑格与相邻的白格连边,流量为oo。因此,最小割是简单割,即最小权覆盖集。

2。由于独立集与覆盖集是互补的,所以最小权覆盖集+最大权独立集=总权值。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #define MAXL 210
  5 #define MAXN 100010
  6 #define MAXM 1000010
  7 #define oo 123456789
  8 using namespace std;
  9 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
 10 int n, m;
 11 int src, des;
 12 int arr[MAXL][MAXL];
 13 int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
 14 inline void addEdge(int x, int y, int val) {
 15     v[e] = y;
 16     cost[e] = val;
 17     next[e] = first[x];
 18     first[x] = e++;
 19 
 20     v[e] = x;
 21     cost[e] = 0;
 22     next[e] = first[y];
 23     first[y] = e++;
 24 }
 25 int SAP() {
 26     int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
 27     int flow = 0;
 28     int aug = oo;
 29     int x, y;
 30     bool flag;
 31     for (int i = 0; i < n; i++) {
 32         cur[i] = first[i];
 33         gap[i] = dis[i] = 0;
 34     }
 35     gap[src] = n;
 36     x = pre[src] = src;
 37     while (dis[src] < n) {
 38         flag = false;
 39         for (int &j = cur[x]; j != -1; j = next[j]) {
 40             y = v[j];
 41             if (cost[j] > 0 && dis[x] == dis[y] + 1) {
 42                 flag = true;
 43                 aug = min(aug, cost[j]);
 44                 pre[y] = x;
 45                 x = y;
 46                 if (x == des) {
 47                     flow += aug;
 48                     while (x != src) {
 49                         x = pre[x];
 50                         cost[cur[x]] -= aug;
 51                         cost[cur[x] ^ 1] += aug;
 52                     }
 53                     aug = oo;
 54                 }
 55                 break;
 56             }
 57         }
 58         if (flag) {
 59             continue;
 60         }
 61         int tmp = n;
 62         for (int j = first[x]; j != -1; j = next[j]) {
 63             y = v[j];
 64             if (cost[j] > 0 && dis[y] < tmp) {
 65                 tmp = dis[y];
 66                 cur[x] = j;
 67             }
 68         }
 69         if ((--gap[dis[x]]) == 0) {
 70             break;
 71         }
 72         gap[dis[x] = tmp + 1]++;
 73         x = pre[x];
 74     }
 75     return flow;
 76 }
 77 int getIndex(int x, int y) {
 78     return (x - 1) * m + y;
 79 }
 80 int main() {
 81     int i, j, k;
 82     int x, y;
 83     int ans;
 84     while (~scanf("%d%d", &n, &m)) {
 85         src = 0;
 86         des = m * n + 1;
 87         e = 0;
 88         memset(first, -1, sizeof(first));
 89         ans = 0;
 90         for (i = 1; i <= n; i++) {
 91             for (j = 1; j <= m; j++) {
 92                 scanf("%d", &arr[i][j]);
 93                 ans += arr[i][j];
 94                 if ((i + j) & 1) {
 95                     addEdge(src, getIndex(i, j), arr[i][j]);
 96                     for (k = 0; k < 4; k++) {
 97                         x = i + go[k][0];
 98                         y = j + go[k][1];
 99                         if (x > 0 && x <= n && y > 0 && y <= m) {
100                             addEdge(getIndex(i, j), getIndex(x, y), oo);
101                         }
102                     }
103                 } else {
104                     addEdge(getIndex(i, j), des, arr[i][j]);
105                 }
106             }
107         }
108         n = des + 1;
109         ans = ans - SAP();
110         printf("%d\n", ans);
111     }
112     return 0;
113 }

(10)餐巾计划问题:线性规划网络优化。

思路:

1。由于第i天的新餐巾可以由i-m天的脏餐巾洗来,因此考虑按天数建模。

2。每天的餐巾有新旧之分,则考虑拆点,每天的新餐巾数量和每天的旧餐巾数量。

3。新餐巾可以直接买来。

4。新餐巾可以由前些天的旧餐巾洗来。

5。旧餐巾可以由上一天的旧餐巾积累而来。

6。求最小费用最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 #define oo 123456
  6 #define MAXN 100010
  7 #define MAXM 1000010
  8 using namespace std;
  9 int V, e;
 10 int src, des;
 11 int lk[MAXN], father[MAXN];
 12 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 13 int dis[MAXN];
 14 bool inq[MAXN];
 15 
 16 int arr[MAXN];
 17 void addEdge(int x, int y, int f, int c) {
 18     v[e] = y;
 19     flow[e] = f;
 20     cost[e] = c;
 21     next[e] = first[x];
 22     first[x] = e++;
 23 
 24     v[e] = x;
 25     flow[e] = 0;
 26     cost[e] = -c;
 27     next[e] = first[y];
 28     first[y] = e++;
 29 }
 30 bool SPFA() {
 31     int i, u;
 32     deque<int> q;
 33     memset(inq, false, sizeof(inq));
 34     for (i = 0; i <= V; i++) {
 35         dis[i] = oo;
 36     }
 37     dis[src] = 0;
 38     q.push_back(src);
 39     inq[src] = true;
 40     while (!q.empty()) {
 41         u = q.front();
 42         q.pop_front();
 43         inq[u] = false;
 44         for (i = first[u]; i != -1; i = next[i]) {
 45             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 46                 dis[v[i]] = dis[u] + cost[i];
 47                 father[v[i]] = u;
 48                 lk[v[i]] = i;
 49                 if (!inq[v[i]]) {
 50                     inq[v[i]] = true;
 51                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 52                         q.push_front(v[i]);
 53                     } else {
 54                         q.push_back(v[i]);
 55                     }
 56                 }
 57             }
 58         }
 59     }
 60     return dis[des] != oo;
 61 }
 62 int MinCostMaxFlow() {
 63     int u;
 64     int ans;
 65     int tmp;
 66     for (ans = 0; SPFA();) {
 67         tmp = oo;
 68         for (u = des; u; u = father[u]) {
 69             tmp = min(tmp, flow[lk[u]]);
 70         }
 71         for (u = des; u; u = father[u]) {
 72             flow[lk[u]] -= tmp;
 73             flow[lk[u] ^ 1] += tmp;
 74         }
 75         ans += tmp * dis[des];
 76     }
 77     return ans;
 78 }
 79 int main() {
 80     int i;
 81     int n;
 82     int buy, fastCost, slowCost, slowDay, fastDay;
 83     while (~scanf("%d%d%d%d%d%d", &n, &buy, &fastDay, &fastCost, &slowDay,
 84             &slowCost)) {
 85         e = 0;
 86         src = 0;
 87         des = n + n + 1;
 88         V = des;
 89         memset(first, -1, sizeof(first));
 90         for (i = 1; i <= n; i++) {
 91             scanf("%d", &arr[i]);
 92             addEdge(2 * i, des, arr[i], 0);
 93             addEdge(src, 2 * i, arr[i], buy);
 94             addEdge(src, 2 * i - 1, arr[i], 0);
 95         }
 96         for (i = 2; i <= n; i++) {
 97             addEdge(2 * (i - 1) - 1, 2 * i - 1, oo, 0);
 98         }
 99         for (i = 1; i <= n; i++) {
100             if (i + fastDay <= n) {
101                 addEdge(2 * i - 1, 2 * (i + fastDay), oo, fastCost);
102             }
103             if (i + slowDay <= n) {
104                 addEdge(2 * i - 1, 2 * (i + slowDay), oo, slowCost);
105             }
106         }
107         for (i = 1; i <= n; i++) {
108             addEdge(src, i, oo, buy);
109         }
110         printf("%d\n", MinCostMaxFlow());
111     }
112     return 0;
113 }

(11)航空路线问题:最长不相交路径。

思路:

1。从东->西,再从西->东。相当于从东->西两条不相交的路径。

2。要求路径最长,则考虑最大费用最大流。

View Code
  1 #include<iostream>
  2 #include<algorithm>
  3 #include<string>
  4 #include<cstring>
  5 #include<queue>
  6 #include<vector>
  7 #include<map>
  8 #define oo 0x7FFFFFFF
  9 #define MAXL 110
 10 #define MAXN 10010
 11 #define MAXM 1000010
 12 using namespace std;
 13 int V, n, m, e;
 14 int src, des;
 15 int lk[MAXN], father[MAXN];
 16 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 17 int dis[MAXN];
 18 bool inq[MAXN];
 19 
 20 vector<string> city;
 21 map<string, int> mymap;
 22 vector<int> res;
 23 bool g[MAXL][MAXL];
 24 bool vis[MAXN];
 25 void addEdge(int x, int y, int f, int c) {
 26     v[e] = y;
 27     flow[e] = f;
 28     cost[e] = c;
 29     next[e] = first[x];
 30     first[x] = e++;
 31 
 32     v[e] = x;
 33     flow[e] = 0;
 34     cost[e] = -c;
 35     next[e] = first[y];
 36     first[y] = e++;
 37 }
 38 bool SPFA() {
 39     int i, u;
 40     deque<int> q;
 41     memset(inq, false, sizeof(inq));
 42     for (i = 0; i <= V; i++) {
 43         dis[i] = oo;
 44     }
 45     dis[src] = 0;
 46     q.push_back(src);
 47     inq[src] = true;
 48     while (!q.empty()) {
 49         u = q.front();
 50         q.pop_front();
 51         inq[u] = false;
 52         for (i = first[u]; i != -1; i = next[i]) {
 53             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 54                 dis[v[i]] = dis[u] + cost[i];
 55                 father[v[i]] = u;
 56                 lk[v[i]] = i;
 57                 if (!inq[v[i]]) {
 58                     inq[v[i]] = true;
 59                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 60                         q.push_front(v[i]);
 61                     } else {
 62                         q.push_back(v[i]);
 63                     }
 64                 }
 65             }
 66         }
 67     }
 68     return dis[des] != oo;
 69 }
 70 int MinCostMaxFlow(int tot) {
 71     int u;
 72     int ans;
 73     int tmp;
 74     int flux;
 75     for (ans = flux = 0; SPFA();) {
 76         tmp = oo;
 77         for (u = des; u; u = father[u]) {
 78             tmp = min(tmp, flow[lk[u]]);
 79         }
 80         for (u = des; u; u = father[u]) {
 81             flow[lk[u]] -= tmp;
 82             flow[lk[u] ^ 1] += tmp;
 83         }
 84         ans += tmp * dis[des];
 85         flux += tmp;
 86     }
 87     if (flux != tot) {
 88         return oo;
 89     } else {
 90         return ans;
 91     }
 92 }
 93 void dfs(int x) {
 94     vis[x] = true;
 95     int i;
 96     res.push_back(x >> 1);
 97     for (i = first[x]; i != -1; i = next[i]) {
 98         if ((i & 1) == 0 && flow[i] == 0 && !vis[v[i]]) {
 99             dfs(v[i]);
100         }
101     }
102 }
103 int main() {
104     int i, j;
105     string str1, str2;
106     int ans;
107     bool flag;
108     while (cin >> n >> m) {
109         memset(g, false, sizeof(g));
110         src = 0;
111         des = n + n - 1;
112         V = des;
113         e = 0;
114         memset(first, -1, sizeof(first));
115         city.clear();
116         mymap.clear();
117         addEdge(0, 1, 2, 0);
118         addEdge(des - 1, des, 2, 0);
119         for (i = 2; i < des - 1; i += 2) {
120             addEdge(i, i + 1, 1, 0);
121         }
122         for (i = 0; i < n; i++) {
123             cin >> str1;
124             city.push_back(str1);
125             mymap[str1] = i << 1;
126         }
127         while (m--) {
128             cin >> str1 >> str2;
129             i = mymap[str1];
130             j = mymap[str2];
131             if (i > j) {
132                 swap(i, j);
133             }
134             addEdge(i ^ 1, j, 1, -1);
135             g[i / 2][j / 2] = g[j / 2][i / 2] = true;
136         }
137         ans = MinCostMaxFlow(2);
138         if (ans == oo) {
139             if (g[0][n - 1]) {
140                 cout << 2 << endl;
141                 cout << city[0] << endl;
142                 cout << city[n - 1] << endl;
143                 cout << city[0] << endl;
144             } else {
145                 cout << "No Solution!" << endl;
146             }
147         } else {
148             cout << -ans << endl;
149             memset(vis, false, sizeof(vis));
150             flag = false;
151             cout << city[0] << endl;
152             for (i = first[1]; i != -1; i = next[i]) {
153                 if ((i & 1) == 0 && flow[i] == 0 && !vis[v[i]]) {
154                     res.clear();
155                     dfs(v[i]);
156                     if (flag) {
157                         reverse(res.begin(), res.end());
158                     } else {
159                         flag = true;
160                     }
161                     res.resize(unique(res.begin(), res.end()) - res.begin());
162                     for (j = 0; j < (int) res.size(); j++) {
163                         cout << city[res[j]] << endl;
164                     }
165                 }
166             }
167             cout << city[0] << endl;
168         }
169     }
170     return 0;
171 }

(12)软件补丁问题:最小转移代价。

思路:

1。只有20个补丁,很容易想到状态压缩。

2。最多(1<<20)个状态,一个状态到另一个状态间有一个花费。

3。求最短花费,就是最短路了。

题目描述有错:第二个字符串中'-'是f1的,'+'是f2的。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #define oo 0x7FFFFFFF
 5 #define MAXN 1<<20
 6 #define MAXM 110
 7 using namespace std;
 8 int dis[MAXN];
 9 bool inq[MAXN];
10 struct patch {
11     int b1, b2;
12     int f1, f2;
13     int cost;
14 } p[MAXM];
15 int n, m;
16 void update(char str[], int &x, int &y) {
17     int i;
18     x = y = 0;
19     for (i = 0; str[i]; i++) {
20         if (str[i] == '+') {
21             x |= 1 << i;
22         } else if (str[i] == '-') {
23             y |= 1 << i;
24         }
25     }
26 }
27 void spfa(int src) {
28     int i;
29     int x, y;
30     deque<int> q;
31     memset(inq, false, sizeof(inq));
32     for (i = 0; i < (1 << n); i++) {
33         dis[i] = oo;
34     }
35     dis[src] = 0;
36     q.push_back(src);
37     while (!q.empty()) {
38         x = q.front();
39         q.pop_front();
40         inq[x] = false;
41         for (i = 0; i < m; i++) {
42             if ((x | p[i].b1) == x && (x & p[i].b2) == 0) {
43                 y = x & (~p[i].f1);
44                 y |= p[i].f2;
45                 if (dis[y] > dis[x] + p[i].cost) {
46                     dis[y] = dis[x] + p[i].cost;
47                     if (!inq[y]) {
48                         if (!q.empty() && dis[y] <= dis[q.front()]) {
49                             q.push_front(y);
50                         } else {
51                             q.push_back(y);
52                         }
53                         inq[y] = true;
54                     }
55                 }
56             }
57         }
58     }
59 }
60 int main() {
61     int i;
62     char a[MAXM], b[MAXM];
63     while (~scanf("%d%d", &n, &m)) {
64         for (i = 0; i < m; i++) {
65             scanf("%d %s %s", &p[i].cost, a, b);
66             update(a, p[i].b1, p[i].b2);
67             update(b, p[i].f2, p[i].f1);
68         }
69         spfa((1 << n) - 1);
70         if (dis[0] == oo) {
71             puts("0");
72         } else {
73             printf("%d\n", dis[0]);
74         }
75     }
76     return 0;
77 }

(13)星际转移问题:网络判定。

思路:

1。枚举天数。随着天数的增加,不断增加点和边。

2。判最大流是否大于等于K。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<vector>
  5 #define oo 123456
  6 #define MAXN 1010
  7 #define MAXM 100010
  8 using namespace std;
  9 int src;
 10 int des;
 11 int V;
 12 int ans;
 13 vector<int> path[MAXN];
 14 vector<int> cap;
 15 vector<int> ind[MAXN];
 16 vector<int> pos[MAXN];
 17 int G[MAXN][MAXN];
 18 int first[MAXN], next[MAXN], v[MAXN], e;
 19 bool vis[MAXN];
 20 int BFS() {
 21     queue<int> q;
 22     int tmp, i, u, v, head, p[MAXN];
 23     memset(p, -1, sizeof(p));
 24     p[src] = src;
 25     q.push(src);
 26     while (!q.empty()) {
 27         head = q.front();
 28         q.pop();
 29         for (i = 1; i <= V; i++) {
 30             if (G[head][i] > 0 && p[i] == -1) {
 31                 p[i] = head;
 32                 q.push(i);
 33             }
 34         }
 35     }
 36     if (p[des] == -1)
 37         return 0;
 38     for (tmp = oo, u = des; p[u] != u;) {
 39         v = u;
 40         u = p[u];
 41         tmp = min(tmp, G[u][v]);
 42     }
 43     for (u = des; p[u] != u;) {
 44         v = u;
 45         u = p[u];
 46         G[u][v] -= tmp;
 47         G[v][u] += tmp;
 48     }
 49     return tmp;
 50 }
 51 void EdmondsKarp() {
 52     int tmp;
 53     for (; (tmp = BFS()); ans += tmp)
 54         ;
 55 }
 56 inline void addEdge(int x, int y) {
 57     next[e] = first[x];
 58     v[e] = y;
 59     first[x] = e++;
 60 }
 61 bool dfs(int x) {
 62     int i;
 63     int y;
 64     vis[x] = true;
 65     for (i = first[x]; i != -1; i = next[i]) {
 66         y = v[i];
 67         if (!vis[y]) {
 68             if (dfs(y)) {
 69                 return true;
 70             }
 71         }
 72     }
 73     return x == des;
 74 }
 75 int main() {
 76     int n, m, k;
 77     int i, j, t;
 78     int tmp;
 79     int day;
 80     int tot;
 81     while (~scanf("%d%d%d", &n, &m, &k)) {
 82         cap.clear();
 83         for (i = 0; i < m; i++) {
 84             scanf("%d%d", &j, &tmp);
 85             cap.push_back(j);
 86             while (tmp--) {
 87                 scanf("%d", &j);
 88                 j += 3;
 89                 path[i].push_back(j);
 90             }
 91         }
 92         src = 3;
 93         des = 2;
 94         e = 0;
 95         memset(first, -1, sizeof(first));
 96         memset(vis, false, sizeof(vis));
 97         for (i = 0; i < m; i++) {
 98             for (j = 0; j < (int) path[i].size(); j++) {
 99                 addEdge(path[i][j], path[i][(j + 1) % path[i].size()]);
100                 addEdge(path[i][j + 1] % path[i].size(), path[i][j]);
101             }
102         }
103         if (dfs(src)) {
104             ans = 0;
105             memset(G, 0, sizeof(G));
106             src = 0;
107             des = 1;
108             tot = 2;
109             for (i = 0; i < m; i++) {
110                 ind[i].clear();
111                 pos[i].clear();
112                 ind[i].push_back(tot++);
113                 pos[i].push_back(path[i][0]);
114             }
115             for (i = 0; i < m; i++) {
116                 if (pos[i][0] == 3) {
117                     G[src][ind[i][0]] = oo;
118                 } else if (pos[i][0] == 2) {
119                     G[ind[i][0]][des] = oo;
120                 }
121             }
122             for (day = 1; ans < k; day++) {
123                 for (i = 0; i < m; i++) {
124                     ind[i].push_back(tot++);
125                     pos[i].push_back(path[i][day % (path[i].size())]);
126                     G[ind[i][day - 1]][ind[i][day]] = cap[i];
127                 }
128                 for (i = 0; i < m; i++) {
129                     for (j = 0; j < m; j++) {
130                         for (t = 0; t <= day; t++) {
131                             if (pos[j][t] == pos[i][day]) {
132                                 G[ind[j][t]][ind[i][day]] = oo;
133                             }
134                         }
135                     }
136                 }
137                 for (i = 0; i < m; i++) {
138                     if (pos[i][day] == 3) {
139                         G[src][ind[i][day]] = oo;
140                     } else if (pos[i][day] == 2) {
141                         G[ind[i][day]][des] = oo;
142                     }
143                 }
144                 V = tot;
145                 EdmondsKarp();
146             }
147             printf("%d\n", day - 1);
148         } else {
149             puts("0");
150         }
151     }
152     return 0;
153 }

(14)孤岛营救问题:分层图最短路径。 

 思路:

对钥匙种类状态压缩。dp[i][j][k]表示在(i,j),钥匙种类为k的最短路。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #define MAXN 11
 5 #define oo 123456789
 6 using namespace std;
 7 int dp[MAXN][MAXN][1 << MAXN];
 8 int g[MAXN][MAXN][MAXN][MAXN];
 9 int mp[MAXN][MAXN];
10 int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
11 struct node {
12     int x;
13     int y;
14     int key;
15     int dis;
16 };
17 int n, m, p;
18 inline bool canMove(int x0, int y0, int x1, int y1, int key) {
19     int tmp = g[x0][y0][x1][y1];
20     if (tmp == -1) {
21         return true;
22     } else if (tmp == 0) {
23         return false;
24     } else if (key & (1 << (tmp - 1))) {
25         return true;
26     } else {
27         return false;
28     }
29 }
30 int bfs() {
31     node head, tmp;
32     queue<node> q;
33     int ans;
34     int i, j, k;
35     for (i = 1; i <= n; i++) {
36         for (j = 1; j <= m; j++) {
37             for (k = 0; k < (1 << p); k++)
38                 dp[i][j][k] = oo;
39         }
40     }
41     head.x = head.y = 1;
42     head.key = 0;
43     head.dis = 0;
44     q.push(head);
45     while (!q.empty()) {
46         head = q.front();
47         q.pop();
48         for (i = 0; i < 4; i++) {
49             tmp.x = head.x + go[i][0];
50             tmp.y = head.y + go[i][1];
51             if (tmp.x > 0 && tmp.x <= n && tmp.y > 0 && tmp.y <= m
52                     && canMove(head.x, head.y, tmp.x, tmp.y, head.key)) {
53                 tmp.dis = head.dis + 1;
54                 tmp.key = head.key;
55                 tmp.key |= mp[tmp.x][tmp.y];
56                 if (tmp.dis < dp[tmp.x][tmp.y][tmp.key]) {
57                     dp[tmp.x][tmp.y][tmp.key] = tmp.dis;
58                     q.push(tmp);
59                 }
60             }
61         }
62     }
63     ans = oo;
64     for (i = 0; i < (1 << p); i++) {
65         ans = min(ans, dp[n][m][i]);
66     }
67     if (ans == oo) {
68         return -1;
69     } else {
70         return ans;
71     }
72 }
73 int main() {
74     int i, j;
75     int x0, y0, x1, y1;
76     while (~scanf("%d%d%d", &n, &m, &p)) {
77         memset(g, -1, sizeof(g));
78         memset(mp, 0, sizeof(mp));
79         scanf("%d", &i);
80         while (i--) {
81             scanf("%d%d%d%d%d", &x0, &y0, &x1, &y1, &j);
82             g[x0][y0][x1][y1] = g[x1][y1][x0][y0] = j;
83         }
84         scanf("%d", &i);
85         while (i--) {
86             scanf("%d%d%d", &x0, &y0, &j);
87             mp[x0][y0] |= 1 << (j - 1);
88         }
89         printf("%d\n", bfs());
90     }
91     return 0;
92 }

(15)汽车加油行驶问题:分层图最短路径。 

 思路:

dp[i][j][k]表示在(i,j),油量为k的最少花费。

View Code
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #define MAXN 110
 5 #define MAXM 15
 6 #define oo 123456789
 7 using namespace std;
 8 int dp[MAXN][MAXN][MAXM];
 9 int n, k, a, b, c;
10 int g[MAXN][MAXN];
11 struct node {
12     int x;
13     int y;
14     int gass;
15     int cost;
16 };
17 int go[4][2] = { { 1, 0 }, { -1, 0 }, { 0, 1 }, { 0, -1 } };
18 int spfa() {
19     int i, j, l;
20     int ans;
21     node head, tmp;
22     queue<node> q;
23     for (i = 0; i <= n; i++) {
24         for (j = 0; j <= n; j++) {
25             for (l = 0; l <= k; l++) {
26                 dp[i][j][l] = oo;
27             }
28         }
29     }
30     dp[1][1][k] = 0;
31     head.x = head.y = 1;
32     head.gass = k;
33     head.cost = 0;
34     q.push(head);
35     while (!q.empty()) {
36         head = q.front();
37         q.pop();
38         if (head.gass == 0) {
39             continue;
40         }
41         for (i = 0; i < 4; i++) {
42             tmp.x = head.x + go[i][0];
43             tmp.y = head.y + go[i][1];
44             if (tmp.x > 0 && tmp.x <= n && tmp.y > 0 && tmp.y <= n) {
45                 tmp.gass = head.gass - 1;
46                 tmp.cost = head.cost;
47                 if (tmp.x < head.x || tmp.y < head.y) {
48                     tmp.cost += b;
49                 }
50                 if (g[tmp.x][tmp.y]) {
51                     tmp.gass = k;
52                     tmp.cost += a;
53                 }
54                 if (tmp.cost < dp[tmp.x][tmp.y][tmp.gass]) {
55                     dp[tmp.x][tmp.y][tmp.gass] = tmp.cost;
56                     q.push(tmp);
57                 }
58                 if (!g[tmp.x][tmp.y]) {
59                     tmp.gass = k;
60                     tmp.cost += a + c;
61                     if (tmp.cost < dp[tmp.x][tmp.y][tmp.gass]) {
62                         dp[tmp.x][tmp.y][tmp.gass] = tmp.cost;
63                         q.push(tmp);
64                     }
65                 }
66             }
67         }
68     }
69     ans = oo;
70     for (i = 0; i <= k; i++) {
71         ans = min(ans, dp[n][n][i]);
72     }
73     return ans;
74 }
75 int main() {
76     int i, j;
77     while (~scanf("%d%d%d%d%d", &n, &k, &a, &b, &c)) {
78         for (i = 1; i <= n; i++) {
79             for (j = 1; j <= n; j++) {
80                 scanf("%d", &g[i][j]);
81             }
82         }
83         printf("%d\n", spfa());
84     }
85     return 0;
86 }

(16)数字梯形问题:最大权不相交路径。

 思路:

规则1:拆点,点与点之间流量都为1。

规则2:不拆点,点与点流量为1。

规则3:不拆点,点与点流量为无穷。

添加源点,汇点。求最小费用最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<vector>
  5 #define oo 0x7FFFFFFF
  6 #define MAXN 10010
  7 #define MAXM 1000010
  8 using namespace std;
  9 int V, n, m, e;
 10 int src, des;
 11 int link[MAXN], father[MAXN];
 12 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 13 int dis[MAXN];
 14 bool inq[MAXN];
 15 
 16 vector<int> arr[MAXN];
 17 vector<int> pos[MAXN];
 18 int size;
 19 void addEdge(int x, int y, int f, int c) {
 20     v[e] = y;
 21     flow[e] = f;
 22     cost[e] = c;
 23     next[e] = first[x];
 24     first[x] = e++;
 25 
 26     v[e] = x;
 27     flow[e] = 0;
 28     cost[e] = -c;
 29     next[e] = first[y];
 30     first[y] = e++;
 31 }
 32 bool SPFA() {
 33     int i, u;
 34     deque<int> q;
 35     memset(inq, false, sizeof(inq));
 36     for (i = 0; i <= V; i++) {
 37         dis[i] = oo;
 38     }
 39     dis[src] = 0;
 40     q.push_back(src);
 41     inq[src] = true;
 42     while (!q.empty()) {
 43         u = q.front();
 44         q.pop_front();
 45         inq[u] = false;
 46         for (i = first[u]; i != -1; i = next[i]) {
 47             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 48                 dis[v[i]] = dis[u] + cost[i];
 49                 father[v[i]] = u;
 50                 link[v[i]] = i;
 51                 if (!inq[v[i]]) {
 52                     inq[v[i]] = true;
 53                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 54                         q.push_front(v[i]);
 55                     } else {
 56                         q.push_back(v[i]);
 57                     }
 58                 }
 59             }
 60         }
 61     }
 62     return dis[des] != oo;
 63 }
 64 int MinCostMaxFlow() {
 65     int u;
 66     int ans;
 67     int tmp;
 68     for (ans = 0; SPFA();) {
 69         tmp = oo;
 70         for (u = des; u; u = father[u]) {
 71             tmp = min(tmp, flow[link[u]]);
 72         }
 73         for (u = des; u; u = father[u]) {
 74             flow[link[u]] -= tmp;
 75             flow[link[u] ^ 1] += tmp;
 76         }
 77         ans += tmp * dis[des];
 78     }
 79     return ans;
 80 }
 81 int getIndex(int x) {
 82     return 2 * x - 1;
 83 }
 84 void rule1() {
 85     int i, j;
 86     e = 0;
 87     src = 0;
 88     des = 2 * size + 1;
 89     V = des;
 90     memset(first, -1, sizeof(first));
 91     for (i = 1; i <= size; i++) {
 92         addEdge(getIndex(i), getIndex(i) + 1, 1, 0);
 93     }
 94     for (i = 0; i < (int) arr[1].size(); i++) {
 95         addEdge(src, getIndex(pos[1][i]), 1, -arr[1][i]);
 96     }
 97     for (i = 1; i < n; i++) {
 98         for (j = 0; j < (int) arr[i].size(); j++) {
 99             addEdge(getIndex(pos[i][j]) + 1, getIndex(pos[i + 1][j]), 1,
100                     -arr[i + 1][j]);
101             addEdge(getIndex(pos[i][j]) + 1, getIndex(pos[i + 1][j + 1]), 1,
102                     -arr[i + 1][j + 1]);
103         }
104     }
105     for (j = 0; j < (int) arr[n].size(); j++) {
106         addEdge(getIndex(pos[n][j]) + 1, des, 1, 0);
107     }
108     printf("%d\n", -MinCostMaxFlow());
109 }
110 void rule2() {
111     int i, j;
112     e = 0;
113     src = 0;
114     des = size + 1;
115     V = des;
116     memset(first, -1, sizeof(first));
117     for (i = 0; i < (int) arr[1].size(); i++) {
118         addEdge(src, pos[1][i], 1, -arr[1][i]);
119     }
120     for (i = 1; i < n; i++) {
121         for (j = 0; j < (int) arr[i].size(); j++) {
122             addEdge(pos[i][j], pos[i + 1][j], 1, -arr[i + 1][j]);
123             addEdge(pos[i][j], pos[i + 1][j + 1], 1, -arr[i + 1][j + 1]);
124         }
125     }
126     for (j = 0; j < (int) arr[n].size(); j++) {
127         addEdge(pos[n][j], des, oo, 0);
128     }
129     printf("%d\n", -MinCostMaxFlow());
130 }
131 void rule3() {
132     int i, j;
133     e = 0;
134     src = 0;
135     des = size + 1;
136     V = des;
137     memset(first, -1, sizeof(first));
138     for (i = 0; i < (int) arr[1].size(); i++) {
139         addEdge(src, pos[1][i], 1, -arr[1][i]);
140     }
141     for (i = 1; i < n; i++) {
142         for (j = 0; j < (int) arr[i].size(); j++) {
143             addEdge(pos[i][j], pos[i + 1][j], oo, -arr[i + 1][j]);
144             addEdge(pos[i][j], pos[i + 1][j + 1], oo, -arr[i + 1][j + 1]);
145         }
146     }
147     for (j = 0; j < (int) arr[n].size(); j++) {
148         addEdge(pos[n][j], des, oo, 0);
149     }
150     printf("%d\n", -MinCostMaxFlow());
151 }
152 int main() {
153     int i, j;
154     int tmp;
155     while (~scanf("%d%d", &m, &n)) {
156         size = 0;
157         for (i = 1; i <= n; i++) {
158             arr[i].clear();
159             pos[i].clear();
160             for (j = 0; j < m + i - 1; j++) {
161                 scanf("%d", &tmp);
162                 arr[i].push_back(tmp);
163                 pos[i].push_back(++size);
164             }
165         }
166         rule1();
167         rule2();
168         rule3();
169     }
170     return 0;
171 }

(17)运输问题:网络费用流量。

 思路:

1。最小费用最大流。

2。最大费用最大流,费用乘以-1,求最小费用最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<vector>
  5 #define oo 0x7FFFFFFF
  6 #define MAXL 1010
  7 #define MAXN 10010
  8 #define MAXM 1000010
  9 using namespace std;
 10 int V, n, m, e;
 11 int src, des;
 12 int link[MAXN], father[MAXN];
 13 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 14 int dis[MAXN];
 15 bool inq[MAXN];
 16 
 17 int a[MAXN];
 18 int b[MAXN];
 19 int c[MAXL][MAXL];
 20 void addEdge(int x, int y, int f, int c) {
 21     v[e] = y;
 22     flow[e] = f;
 23     cost[e] = c;
 24     next[e] = first[x];
 25     first[x] = e++;
 26 
 27     v[e] = x;
 28     flow[e] = 0;
 29     cost[e] = -c;
 30     next[e] = first[y];
 31     first[y] = e++;
 32 }
 33 bool SPFA() {
 34     int i, u;
 35     deque<int> q;
 36     memset(inq, false, sizeof(inq));
 37     for (i = 0; i <= V; i++) {
 38         dis[i] = oo;
 39     }
 40     dis[src] = 0;
 41     q.push_back(src);
 42     inq[src] = true;
 43     while (!q.empty()) {
 44         u = q.front();
 45         q.pop_front();
 46         inq[u] = false;
 47         for (i = first[u]; i != -1; i = next[i]) {
 48             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 49                 dis[v[i]] = dis[u] + cost[i];
 50                 father[v[i]] = u;
 51                 link[v[i]] = i;
 52                 if (!inq[v[i]]) {
 53                     inq[v[i]] = true;
 54                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 55                         q.push_front(v[i]);
 56                     } else {
 57                         q.push_back(v[i]);
 58                     }
 59                 }
 60             }
 61         }
 62     }
 63     return dis[des] != oo;
 64 }
 65 int MinCostMaxFlow() {
 66     int u;
 67     int ans;
 68     int tmp;
 69     for (ans = 0; SPFA();) {
 70         tmp = oo;
 71         for (u = des; u; u = father[u]) {
 72             tmp = min(tmp, flow[link[u]]);
 73         }
 74         for (u = des; u; u = father[u]) {
 75             flow[link[u]] -= tmp;
 76             flow[link[u] ^ 1] += tmp;
 77         }
 78         ans += tmp * dis[des];
 79     }
 80     return ans;
 81 }
 82 void calMinCostMaxFlow(int flag) {
 83     int i, j;
 84     src = 0;
 85     des = n + m + 1;
 86     V = des;
 87     e = 0;
 88     memset(first, -1, sizeof(first));
 89     for (i = 1; i <= m; i++) {
 90         addEdge(src, i, a[i], 0);
 91     }
 92     for (i = 1; i <= n; i++) {
 93         addEdge(m + i, des, b[i], 0);
 94     }
 95     for (i = 1; i <= m; i++) {
 96         for (j = 1; j <= n; j++) {
 97             addEdge(i, m + j, oo, c[i][j] * flag);
 98         }
 99     }
100     printf("%d\n", flag * MinCostMaxFlow());
101 }
102 int main() {
103     int i, j;
104     while (~scanf("%d%d", &m, &n)) {
105         for (i = 1; i <= m; i++) {
106             scanf("%d", &a[i]);
107         }
108         for (i = 1; i <= n; i++) {
109             scanf("%d", &b[i]);
110         }
111         for (i = 1; i <= m; i++) {
112             for (j = 1; j <= n; j++) {
113                 scanf("%d", &c[i][j]);
114             }
115         }
116         calMinCostMaxFlow(1);
117         calMinCostMaxFlow(-1);
118     }
119     return 0;
120 }

(18)分配问题:二分图最佳匹配。 

思路:

同(17)运输问题。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<vector>
  5 #define oo 0x7FFFFFFF
  6 #define MAXL 1010
  7 #define MAXN 10010
  8 #define MAXM 1000010
  9 using namespace std;
 10 int V, n, e;
 11 int src, des;
 12 int link[MAXN], father[MAXN];
 13 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 14 int dis[MAXN];
 15 bool inq[MAXN];
 16 
 17 int c[MAXL][MAXL];
 18 void addEdge(int x, int y, int f, int c) {
 19     v[e] = y;
 20     flow[e] = f;
 21     cost[e] = c;
 22     next[e] = first[x];
 23     first[x] = e++;
 24 
 25     v[e] = x;
 26     flow[e] = 0;
 27     cost[e] = -c;
 28     next[e] = first[y];
 29     first[y] = e++;
 30 }
 31 bool SPFA() {
 32     int i, u;
 33     deque<int> q;
 34     memset(inq, false, sizeof(inq));
 35     for (i = 0; i <= V; i++) {
 36         dis[i] = oo;
 37     }
 38     dis[src] = 0;
 39     q.push_back(src);
 40     inq[src] = true;
 41     while (!q.empty()) {
 42         u = q.front();
 43         q.pop_front();
 44         inq[u] = false;
 45         for (i = first[u]; i != -1; i = next[i]) {
 46             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 47                 dis[v[i]] = dis[u] + cost[i];
 48                 father[v[i]] = u;
 49                 link[v[i]] = i;
 50                 if (!inq[v[i]]) {
 51                     inq[v[i]] = true;
 52                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 53                         q.push_front(v[i]);
 54                     } else {
 55                         q.push_back(v[i]);
 56                     }
 57                 }
 58             }
 59         }
 60     }
 61     return dis[des] != oo;
 62 }
 63 int MinCostMaxFlow() {
 64     int u;
 65     int ans;
 66     int tmp;
 67     for (ans = 0; SPFA();) {
 68         tmp = oo;
 69         for (u = des; u; u = father[u]) {
 70             tmp = min(tmp, flow[link[u]]);
 71         }
 72         for (u = des; u; u = father[u]) {
 73             flow[link[u]] -= tmp;
 74             flow[link[u] ^ 1] += tmp;
 75         }
 76         ans += tmp * dis[des];
 77     }
 78     return ans;
 79 }
 80 void calMinCostMaxFlow(int flag) {
 81     int i, j;
 82     src = 0;
 83     des = n + n + 1;
 84     V = des;
 85     e = 0;
 86     memset(first, -1, sizeof(first));
 87     for (i = 1; i <= n; i++) {
 88         for (j = 1; j <= n; j++) {
 89             addEdge(i, n + j, oo, c[i][j] * flag);
 90         }
 91     }
 92     for (i = 1; i <= n; i++) {
 93         addEdge(src, i, 1, 0);
 94         addEdge(n + i, des, 1, 0);
 95     }
 96     printf("%d\n", flag * MinCostMaxFlow());
 97 }
 98 int main() {
 99     int i, j;
100     while (~scanf("%d", &n)) {
101         for (i = 1; i <= n; i++) {
102             for (j = 1; j <= n; j++) {
103                 scanf("%d", &c[i][j]);
104             }
105         }
106         calMinCostMaxFlow(1);
107         calMinCostMaxFlow(-1);
108     }
109     return 0;
110 }

(19)负载平衡问题:最小代价供求。 

思路:

1。向相邻的左右两个点连边,流量为oo,费用为1。

2。若一个点库存比平均值多a,则从源向该点连边,流量为a,费用为0。

3。若一个点库存比平均值少a,则从该点向汇连边,流量为a,费用为0。

4。求最小费用最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #define oo 123456
  5 #define MAXN 100010
  6 #define MAXM 1000010
  7 using namespace std;
  8 int V, n, m, e;
  9 int src, des;
 10 int lk[MAXN], father[MAXN];
 11 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 12 int dis[MAXN];
 13 bool inq[MAXN];
 14 
 15 int arr[MAXN];
 16 void addEdge(int x, int y, int f, int c) {
 17     v[e] = y;
 18     flow[e] = f;
 19     cost[e] = c;
 20     next[e] = first[x];
 21     first[x] = e++;
 22 
 23     v[e] = x;
 24     flow[e] = 0;
 25     cost[e] = -c;
 26     next[e] = first[y];
 27     first[y] = e++;
 28 }
 29 bool SPFA() {
 30     int i, u;
 31     deque<int> q;
 32     memset(inq, false, sizeof(inq));
 33     for (i = 0; i <= V; i++) {
 34         dis[i] = oo;
 35     }
 36     dis[src] = 0;
 37     q.push_back(src);
 38     inq[src] = true;
 39     while (!q.empty()) {
 40         u = q.front();
 41         q.pop_front();
 42         inq[u] = false;
 43         for (i = first[u]; i != -1; i = next[i]) {
 44             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 45                 dis[v[i]] = dis[u] + cost[i];
 46                 father[v[i]] = u;
 47                 lk[v[i]] = i;
 48                 if (!inq[v[i]]) {
 49                     inq[v[i]] = true;
 50                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 51                         q.push_front(v[i]);
 52                     } else {
 53                         q.push_back(v[i]);
 54                     }
 55                 }
 56             }
 57         }
 58     }
 59     return dis[des] != oo;
 60 }
 61 int MinCostMaxFlow() {
 62     int u;
 63     int ans;
 64     int tmp;
 65     for (ans = 0; SPFA();) {
 66         tmp = oo;
 67         for (u = des; u; u = father[u]) {
 68             tmp = min(tmp, flow[lk[u]]);
 69         }
 70         for (u = des; u; u = father[u]) {
 71             flow[lk[u]] -= tmp;
 72             flow[lk[u] ^ 1] += tmp;
 73         }
 74         ans += tmp * dis[des];
 75     }
 76     return ans;
 77 }
 78 int main() {
 79     int i, j;
 80     int sum;
 81     while (~scanf("%d", &n)) {
 82         e = 0;
 83         src = 0;
 84         des = n + 1;
 85         V = des;
 86         memset(first, -1, sizeof(first));
 87         sum = 0;
 88         for (i = 1; i <= n; i++) {
 89             scanf("%d", &arr[i]);
 90             sum += arr[i];
 91         }
 92         sum /= n;
 93         for (i = 1; i <= n; i++) {
 94             arr[i] -= sum;
 95             if (arr[i] > 0) {
 96                 addEdge(src, i, arr[i], 0);
 97             } else if (arr[i] < 0) {
 98                 addEdge(i, des, -arr[i], 0);
 99             }
100             j = i + 1;
101             if (j > n) {
102                 j = 1;
103             }
104             addEdge(i, j, oo, 1);
105             addEdge(j, i, oo, 1);
106             j = i - 1;
107             if (j < 1) {
108                 j = n;
109             }
110             addEdge(i, j, oo, 1);
111             addEdge(j, i, oo, 1);
112         }
113         printf("%d\n", MinCostMaxFlow());
114     }
115     return 0;
116 }

(20)深海机器人问题:线性规划网络优化。 

思路:

1。每个权值只能取一次,流量设为1。

2。每条路径可以取多次,流量设为oo。

3。最大费用最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #define oo 123456
  5 #define MAXN 100010
  6 #define MAXM 1000010
  7 using namespace std;
  8 int V, n, m, e;
  9 int src, des;
 10 int lk[MAXN], father[MAXN];
 11 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 12 int dis[MAXN];
 13 bool inq[MAXN];
 14 
 15 void addEdge(int x, int y, int f, int c) {
 16     v[e] = y;
 17     flow[e] = f;
 18     cost[e] = c;
 19     next[e] = first[x];
 20     first[x] = e++;
 21 
 22     v[e] = x;
 23     flow[e] = 0;
 24     cost[e] = -c;
 25     next[e] = first[y];
 26     first[y] = e++;
 27 }
 28 bool SPFA() {
 29     int i, u;
 30     deque<int> q;
 31     memset(inq, false, sizeof(inq));
 32     for (i = 0; i <= V; i++) {
 33         dis[i] = oo;
 34     }
 35     dis[src] = 0;
 36     q.push_back(src);
 37     inq[src] = true;
 38     while (!q.empty()) {
 39         u = q.front();
 40         q.pop_front();
 41         inq[u] = false;
 42         for (i = first[u]; i != -1; i = next[i]) {
 43             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 44                 dis[v[i]] = dis[u] + cost[i];
 45                 father[v[i]] = u;
 46                 lk[v[i]] = i;
 47                 if (!inq[v[i]]) {
 48                     inq[v[i]] = true;
 49                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 50                         q.push_front(v[i]);
 51                     } else {
 52                         q.push_back(v[i]);
 53                     }
 54                 }
 55             }
 56         }
 57     }
 58     return dis[des] != oo;
 59 }
 60 int MinCostMaxFlow() {
 61     int u;
 62     int ans;
 63     int tmp;
 64     for (ans = 0; SPFA();) {
 65         tmp = oo;
 66         for (u = des; u; u = father[u]) {
 67             tmp = min(tmp, flow[lk[u]]);
 68         }
 69         for (u = des; u; u = father[u]) {
 70             flow[lk[u]] -= tmp;
 71             flow[lk[u] ^ 1] += tmp;
 72         }
 73         ans += tmp * dis[des];
 74     }
 75     return ans;
 76 }
 77 int main() {
 78     int a, b;
 79     int p, q;
 80     int i, j;
 81     int x, y, val;
 82     while (~scanf("%d%d%d%d", &a, &b, &p, &q)) {
 83         e = 0;
 84         src = 0;
 85         des = (p + 1) * (q + 1) + 1;
 86         V = des;
 87         memset(first, -1, sizeof(first));
 88         for (i = 0; i <= p; i++) {
 89             for (j = 1; j <= q; j++) {
 90                 scanf("%d", &x);
 91                 addEdge(i * (q + 1) + j, i * (q + 1) + j + 1, 1, -x);
 92                 addEdge(i * (q + 1) + j, i * (q + 1) + j + 1, oo, 0);
 93             }
 94         }
 95         for (i = 0; i <= q; i++) {
 96             for (j = 1; j <= p; j++) {
 97                 scanf("%d", &x);
 98                 addEdge((j - 1) * (q + 1) + i + 1, j * (q + 1) + i + 1, 1, -x);
 99                 addEdge((j - 1) * (q + 1) + i + 1, j * (q + 1) + i + 1, oo, 0);
100             }
101         }
102         while (a--) {
103             scanf("%d%d%d", &val, &y, &x);
104             addEdge(src, y * (q + 1) + x + 1, val, 0);
105         }
106         while (b--) {
107             scanf("%d%d%d", &val, &y, &x);
108             addEdge(y * (q + 1) + x + 1, des, val, 0);
109         }
110         printf("%d\n", -MinCostMaxFlow());
111     }
112 }

(21)最长k可重区间集问题:最大权不相交路径。 

思路:

1。对所有端点排序后,离散化。

2。源到1,流量为k,费用为0。最后一个点到汇,流量为oo,费用为0。

3。若有区间[x,y],则x向y连边,流量为1,费用为x-y。

4。最大费用最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<queue>
  4 #include<algorithm>
  5 #define oo 123456
  6 #define MAXN 100010
  7 #define MAXM 1000010
  8 using namespace std;
  9 int V, n, m, e;
 10 int src, des;
 11 int lk[MAXN], father[MAXN];
 12 int first[MAXN], cost[MAXM], flow[MAXM], next[MAXM], v[MAXM];
 13 int dis[MAXN];
 14 bool inq[MAXN];
 15 
 16 int arr[MAXN];
 17 int size;
 18 struct point {
 19     int x, y;
 20 } p[MAXN];
 21 void addEdge(int x, int y, int f, int c) {
 22     v[e] = y;
 23     flow[e] = f;
 24     cost[e] = c;
 25     next[e] = first[x];
 26     first[x] = e++;
 27 
 28     v[e] = x;
 29     flow[e] = 0;
 30     cost[e] = -c;
 31     next[e] = first[y];
 32     first[y] = e++;
 33 }
 34 bool SPFA() {
 35     int i, u;
 36     deque<int> q;
 37     memset(inq, false, sizeof(inq));
 38     for (i = 0; i <= V; i++) {
 39         dis[i] = oo;
 40     }
 41     dis[src] = 0;
 42     q.push_back(src);
 43     inq[src] = true;
 44     while (!q.empty()) {
 45         u = q.front();
 46         q.pop_front();
 47         inq[u] = false;
 48         for (i = first[u]; i != -1; i = next[i]) {
 49             if (flow[i] && dis[v[i]] > dis[u] + cost[i]) {
 50                 dis[v[i]] = dis[u] + cost[i];
 51                 father[v[i]] = u;
 52                 lk[v[i]] = i;
 53                 if (!inq[v[i]]) {
 54                     inq[v[i]] = true;
 55                     if (!q.empty() && dis[v[i]] <= dis[q.front()]) {
 56                         q.push_front(v[i]);
 57                     } else {
 58                         q.push_back(v[i]);
 59                     }
 60                 }
 61             }
 62         }
 63     }
 64     return dis[des] != oo;
 65 }
 66 int MinCostMaxFlow() {
 67     int u;
 68     int ans;
 69     int tmp;
 70     for (ans = 0; SPFA();) {
 71         tmp = oo;
 72         for (u = des; u; u = father[u]) {
 73             tmp = min(tmp, flow[lk[u]]);
 74         }
 75         for (u = des; u; u = father[u]) {
 76             flow[lk[u]] -= tmp;
 77             flow[lk[u] ^ 1] += tmp;
 78         }
 79         ans += tmp * dis[des];
 80     }
 81     return ans;
 82 }
 83 int main() {
 84     int i;
 85     int m;
 86     int x, y;
 87     while (~scanf("%d%d", &n, &m)) {
 88         e = 0;
 89         src = 0;
 90         des = n + n + 1;
 91         V = des;
 92         memset(first, -1, sizeof(first));
 93         size = 0;
 94         for (i = 0; i < n; i++) {
 95             scanf("%d%d", &p[i].x, &p[i].y);
 96             arr[size++] = p[i].x;
 97             arr[size++] = p[i].y;
 98         }
 99         sort(arr, arr + size);
100         size = unique(arr, arr + size) - arr;
101         addEdge(src, 1, m, 0);
102         addEdge(size, des, oo, 0);
103         for (i = 2; i <= size; i++) {
104             addEdge(i - 1, i, oo, 0);
105         }
106         for (i = 0; i < n; i++) {
107             x = lower_bound(arr, arr + size, p[i].x) - arr + 1;
108             y = lower_bound(arr, arr + size, p[i].y) - arr + 1;
109             addEdge(x, y, 1, p[i].x - p[i].y);
110         }
111         printf("%d\n", -MinCostMaxFlow());
112     }
113     return 0;
114 }

(24)骑士共存问题:二分图最大独立集。

思路:

1。冲突的位置相互连边。

2.。添加源,汇。

3。求最大流。

View Code
  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #define MAXL 210
  5 #define MAXN 100010
  6 #define MAXM 1000010
  7 #define oo 0x7FFFFFFF
  8 using namespace std;
  9 int first[MAXN], next[MAXM], v[MAXM], cost[MAXM], e;
 10 int n;
 11 int src, des;
 12 bool flag[MAXL][MAXL];
 13 int go[][2] = { { 1, 2 }, { 1, -2 }, { -1, 2 }, { -1, -2 }, { 2, 1 }, { 2, -1 },
 14         { -2, 1 }, { -2, -1 } };
 15 inline void addEdge(int x, int y, int val) {
 16     v[e] = y;
 17     cost[e] = val;
 18     next[e] = first[x];
 19     first[x] = e++;
 20 
 21     v[e] = x;
 22     cost[e] = 0;
 23     next[e] = first[y];
 24     first[y] = e++;
 25 }
 26 int SAP() {
 27     int pre[MAXN], cur[MAXN], dis[MAXN], gap[MAXN];
 28     int flow = 0;
 29     int aug = oo;
 30     int x, y;
 31     bool flag;
 32     for (int i = 0; i < n; i++) {
 33         cur[i] = first[i];
 34         gap[i] = dis[i] = 0;
 35     }
 36     gap[src] = n;
 37     x = pre[src] = src;
 38     while (dis[src] < n) {
 39         flag = false;
 40         for (int &j = cur[x]; j != -1; j = next[j]) {
 41             y = v[j];
 42             if (cost[j] > 0 && dis[x] == dis[y] + 1) {
 43                 flag = true;
 44                 aug = min(aug, cost[j]);
 45                 pre[y] = x;
 46                 x = y;
 47                 if (x == des) {
 48                     flow += aug;
 49                     while (x != src) {
 50                         x = pre[x];
 51                         cost[cur[x]] -= aug;
 52                         cost[cur[x] ^ 1] += aug;
 53                     }
 54                     aug = oo;
 55                 }
 56                 break;
 57             }
 58         }
 59         if (flag) {
 60             continue;
 61         }
 62         int tmp = n;
 63         for (int j = first[x]; j != -1; j = next[j]) {
 64             y = v[j];
 65             if (cost[j] > 0 && dis[y] < tmp) {
 66                 tmp = dis[y];
 67                 cur[x] = j;
 68             }
 69         }
 70         if ((--gap[dis[x]]) == 0) {
 71             break;
 72         }
 73         gap[dis[x] = tmp + 1]++;
 74         x = pre[x];
 75     }
 76     return flow;
 77 }
 78 int getIndex(int x, int y) {
 79     return (x - 1) * n + y;
 80 }
 81 int main() {
 82     int m;
 83     int i, j, k;
 84     int x, y;
 85     int ans;
 86     while (~scanf("%d%d", &n, &m)) {
 87         src = 0;
 88         des = 2 * n * n + 1;
 89         e = 0;
 90         memset(first, -1, sizeof(first));
 91         memset(flag, false, sizeof(flag));
 92         for (i = 0; i < m; i++) {
 93             scanf("%d%d", &x, &y);
 94             flag[x][y] = true;
 95         }
 96         for (i = 1; i <= n; i++) {
 97             for (j = 1; j <= n; j++) {
 98                 if (flag[i][j]) {
 99                     continue;
100                 }
101                 addEdge(src, getIndex(i, j), 1);
102                 addEdge(n * n + getIndex(i, j), des, 1);
103                 for (k = 0; k < 8; k++) {
104                     x = i + go[k][0];
105                     y = j + go[k][1];
106                     if (x > 0 && x <= n && y > 0 && y <= n && !flag[x][y]) {
107                         addEdge(getIndex(i, j), n * n + getIndex(x, y), 1);
108                     }
109                 }
110             }
111         }
112         ans = n * n - m;
113         n = des + 1;
114         printf("%d\n", ans - SAP() / 2);
115     }
116     return 0;
117 }
新博客:www.zhixiangli.com
原文地址:https://www.cnblogs.com/DrunBee/p/3053598.html