zoukankan      html  css  js  c++  java
  • 【线性规划和网络流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
  • 相关阅读:
    leetcode 155. Min Stack 、232. Implement Queue using Stacks 、225. Implement Stack using Queues
    leetcode 557. Reverse Words in a String III 、151. Reverse Words in a String
    leetcode 153. Find Minimum in Rotated Sorted Array 、154. Find Minimum in Rotated Sorted Array II 、33. Search in Rotated Sorted Array 、81. Search in Rotated Sorted Array II 、704. Binary Search
    leetcode 344. Reverse String 、541. Reverse String II 、796. Rotate String
    leetcode 162. Find Peak Element
    leetcode 88. Merge Sorted Array
    leetcode 74. Search a 2D Matrix 、240. Search a 2D Matrix II
    Android的API版本和名称对应关系
    spring 定时任务执行两次解决办法
    解析字符串为泛型的方法
  • 原文地址:https://www.cnblogs.com/DrunBee/p/3053598.html
Copyright © 2011-2022 走看看