• 【线性规划和网络流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
  • 相关阅读:
    求树的重心
    牛客多校第七场B题
    高精度
    hdu 6763 Total Eclipse 并查集+思维
    substr用法
    置换群
    快速幂
    Winform+Mysql登录
    Rider C#连接MySQL
    C# winform组件
  • 原文地址:https://www.cnblogs.com/DrunBee/p/3053598.html
Copyright © 2020-2023  润新知