zoukankan      html  css  js  c++  java
  • 三种上下界网络流模板

      1 /*
      2     首先建立一个源S和一个汇T,一般称为附加源和附加汇。
      3     对于图中的每条弧<u,v>,假设它容量上界为c,下界b,那么把这条边拆为三条只有上界的弧。
      4     一条为<S,v>,容量为b;
      5   一条为<u,T>,容量为b;
      6   一条为<u,v>,容量为c-b。
      7     其中前两条弧一般称为附加弧。
      8     然后对这张图跑最大流,以S为源,以T为汇,如果所有的附加弧都满流,则原图有可行流;否则就是无解。 
      9     这时,每条非附加弧的流量加上它的容量下界,就是原图中这条弧应该有的流量。
     10     
     11     对于原图中的每条弧,我们把c-b称为它的自由流量,意思就是只要它流满了下界,这些流多少都没问题。
     12   既然如此,对于每条弧<u,v>,我们强制给v提供b单位的流量,并且强制从u那里拿走b单位的流量,这一步对应着两条附加弧。
     13   如果这一系列强制操作能完成的话,也就是有一组可行流了。
     14   注意:这张图的最大流只是对应着原图的一组可行流,而不是原图的最大或最小流。
     15 */
     16 #include <bits/stdc++.h>
     17 using namespace std;
     18 const int oo = (1LL << 31) - 1;
     19 const int LEN = 1e5 + 5;
     20 struct node {
     21     int x, y, l, r;
     22 } a[LEN];
     23 namespace ISAP {
     24     int flow, tot, n, m, src, tar, qh, qt, cnt, ans;
     25     struct edge {
     26         int vet, next, len;
     27     } E[LEN * 2];
     28     int dis[LEN], gap[LEN], head[LEN], cur[LEN], q[LEN], vis[LEN], IN[LEN];
     29     void add(int u, int v, int c) {
     30         E[++tot] = (edge){v, head[u], c};
     31         head[u] = tot;
     32     }
     33     void join(int u, int v, int c) {
     34         add(u, v, c);
     35         add(v, u, 0);
     36     }
     37     void bfs(int s) {
     38         qh = qt = 0;
     39         q[++qt] = s;
     40         dis[s] = 0;
     41         vis[s] = 1;
     42         while (qh < qt) {
     43             int u = q[++qh];
     44             gap[dis[u]]++;
     45             for (int e = head[u]; e != -1; e = E[e].next) {
     46                 int v = E[e].vet;
     47                 if (E[e ^ 1].len && !vis[v]) {
     48                     dis[v] = dis[u] + 1;
     49                     vis[v] = 1;
     50                     q[++qt] = v;
     51                 }
     52             }
     53         }
     54     }
     55     int isap(int u, int aug) {
     56         if (u == tar) return aug;
     57         int flow = 0;
     58         for (int e = head[u]; e != -1; e = E[e].next) {
     59             int v = E[e].vet;
     60             if (E[e].len && dis[v] == dis[u] - 1) {
     61                 int tmp = isap(v, min(aug - flow, E[e].len));
     62                 E[e].len -= tmp;
     63                 E[e ^ 1].len += tmp;
     64                 flow += tmp;
     65                 head[u] = e;
     66                 if (flow == aug || dis[src] == cnt) return flow;
     67             }
     68         }
     69         if (!--gap[dis[u]++]) dis[src] = cnt;
     70         ++gap[dis[u]];
     71         head[u] = cur[u];
     72         return flow;
     73     }
     74     void init() {
     75         tot = -1, gap[0] = 0;
     76         for (int i = 1; i <= cnt; i++) {
     77             dis[i] = gap[i] = vis[i] = IN[i] = 0;
     78             head[i] = -1;
     79         }
     80     }
     81     int maxflow(int s, int t) {
     82         src = s, tar = t;
     83         int res = 0;
     84         for (int i = 1; i <= cnt; i++) cur[i] = head[i];
     85         bfs(tar);
     86         while (dis[src] < cnt) res += isap(src, oo);
     87         return res;
     88     }
     89 }
     90 using namespace ISAP;
     91 int main() {
     92     scanf("%d %d", &n, &m);
     93     cnt = n;
     94     src = ++cnt, tar = ++cnt;
     95     init();
     96     for (int i = 1; i <= m; i++) {
     97         int x, y, l, r;
     98         scanf("%d %d %d %d", &x, &y, &l, &r);
     99         a[i] = (node){x, y, l, r};
    100         join(x, y, r - l);
    101         IN[y] += l, IN[x] -= l;
    102     }
    103     for (int i = 1; i <= n; i++) {
    104         if (IN[i] < 0) join(i, tar, -IN[i]);
    105         else {
    106             join(src, i, IN[i]);
    107             flow += IN[i];
    108         }
    109     }
    110     int ans = maxflow(src, tar);
    111     if (flow == ans) {
    112         puts("YES");
    113         for (int i = 1; i <= m; i++) printf("%d
    ", a[i].l + E[i * 2 - 1].len);
    114     } else puts("NO");
    115     return 0;
    116 }
    无源汇可行流
      1 /*
      2     先来看有源汇可行流
      3   建模方法:
      4   建立弧<t,s>,容量下界为0,上界为oo。 
      5   然后对这个新图(实际上只是比原图多了一条边)按照无源汇可行流的方法建模,
      6     如果所有附加弧满流,则存在可行流。
      7   求原图中每条边对应的实际流量的方法,同无源汇可行流,只是忽略掉弧<t,s>就好。
      8   而且这时候弧<t,s>的流量就是原图的总流量。
      9   理解方法:
     10   有源汇相比无源汇的不同就在于,源和汇是不满足流量平衡的,那么连接<t,s>之后,
     11     源和汇也满足了流量平衡,就可以直接按照无源汇的方式建模。
     12   注意:这张图的最大流只是对应着原图的一组可行流,而不是原图的最大或最小流。
     13 
     14     有源汇最大流
     15   建模方法:
     16   首先按照有源汇可行流的方法建模,如果不存在可行流,更别提什么最大流了。
     17   如果存在可行流,那么在运行过有源汇可行流的图上(就是已经存在流量的那张图,流量不要清零),
     18     跑一遍从s到t的最大流(这里的s和t是原图的源和汇,不是附加源和附加汇),就是原图的最大流。
     19   理解方法:
     20   为什么要在那个已经有了流量的图上跑最大流?因为那张图保证了每条弧的容量下界,在这张图上跑最大流,
     21     实际上就是在容量下界全部满足的前提下尽量多得获得“自由流量”。
     22   注意,在这张已经存在流量的图上,弧<t,s>也是存在流量的,千万不要忽略这条弧。
     23     因为它的相反弧<s,t>的流量为<t,s>的流量的相反数,且<s,t>的容量为0,所以这部分的流量也是会被算上的。
     24 */
     25 #include <bits/stdc++.h>
     26 using namespace std;
     27 typedef long long ll;
     28 const int LEN = 1e5 + 5;
     29 const int oo = (1LL << 31) - 1;
     30 namespace DINIC {
     31     int tot, n, m, src, tar, qh, qt, cnt, s, t, S, T;
     32     int ans, flow;
     33     struct edge {
     34         int vet, next, len;
     35     } E[LEN * 2];
     36     int dis[LEN], gap[LEN], head[LEN], cur[LEN], q[LEN], vis[LEN], IN[LEN];
     37     void add(int u, int v, int c) {
     38         E[++tot] = (edge){v, head[u], c};
     39         head[u] = tot;
     40     }
     41     void join(int u, int v, int c) {
     42         add(u, v, c);
     43         add(v, u, 0);
     44     }
     45     void init() {
     46         tot = -1;
     47         for (int i = 1; i <= cnt; i++) head[i] = -1;
     48     }
     49     bool bfs() {
     50         for (int i = 1; i <= cnt; i++) dis[i] = 0;
     51         qh = qt = 0;
     52         q[++qt] = src;
     53         dis[src] = 1;
     54         while (qh < qt) {
     55             int u = q[++qh];
     56             for (int e = head[u]; e != -1; e = E[e].next) {
     57                 int v = E[e].vet;
     58                 if (E[e].len && !dis[v]) {
     59                     dis[v] = dis[u] + 1;
     60                     if (v == tar) return 1;
     61                     q[++qt] = v;
     62                 }
     63             }
     64         }
     65         return dis[tar];
     66     }
     67     int dfs(int u, int aug) {
     68         if (u == tar || !aug) return aug;
     69         int tmp = 0;
     70         for (int &e = cur[u]; e != -1; e = E[e].next) {
     71             int v = E[e].vet;
     72             if (dis[v] == dis[u] + 1) {
     73                 if (tmp = dfs(v, min(aug, E[e].len))) {
     74                     E[e].len -= tmp;
     75                     E[e ^ 1].len += tmp;
     76                     return tmp;
     77                 }
     78             }
     79         }
     80         return 0;
     81     }
     82     int maxflow(int s, int t) {
     83         src = s, tar = t;
     84         int res = 0, flow = 0;
     85         while (bfs()) {
     86             for (int i = 1; i <= cnt; i++) cur[i] = head[i];
     87             while (flow = dfs(src, oo)) res += flow;
     88         }
     89         return res;
     90     }
     91 }
     92 using namespace DINIC;
     93 int main() {
     94     scanf("%d %d %d %d", &n, &m, &s, &t);
     95     cnt = n;
     96     S = ++cnt, T = ++cnt;
     97     init();
     98     for (int i = 1; i <= m; i++) {
     99         int x, y, l, r;
    100         scanf("%d %d %d %d", &x, &y, &l, &r);
    101         join(x, y, r - l);
    102         IN[y] += l, IN[x] -= l;
    103     } 
    104     for (int i = 1; i <= n; i++) {
    105         if (IN[i] < 0) join(i, T, -IN[i]);
    106         else if (IN[i] > 0) {
    107             flow += IN[i];
    108             join(S, i, IN[i]);
    109         }
    110     }
    111     join(t, s, oo);
    112     ans = maxflow(S, T);
    113     if (ans != flow) puts("please go home to sleep");
    114     else {
    115         ans = maxflow(s, t);
    116         printf("%lld
    ", ans);
    117     }
    118     return 0;
    119 }
    有源汇最大流
      1 /*
      2     先来看有源汇可行流
      3   建模方法:
      4   建立弧<t,s>,容量下界为0,上界为oo。 
      5   然后对这个新图(实际上只是比原图多了一条边)按照无源汇可行流的方法建模,
      6     如果所有附加弧满流,则存在可行流。
      7   求原图中每条边对应的实际流量的方法,同无源汇可行流,只是忽略掉弧<t,s>就好。
      8   而且这时候弧<t,s>的流量就是原图的总流量。
      9   理解方法:
     10   有源汇相比无源汇的不同就在于,源和汇是不满足流量平衡的,那么连接<t,s>之后,
     11     源和汇也满足了流量平衡,就可以直接按照无源汇的方式建模。
     12   注意:这张图的最大流只是对应着原图的一组可行流,而不是原图的最大或最小流。
     13 
     14     有源汇最小流
     15   有源汇最小流的常见建模方法比较多,我就只说我常用的一种。
     16   建模方法:
     17   首先按照有源汇可行流的方法建模,但是不要建立<t,s>这条弧。
     18   然后在这个图上,跑从附加源ss到附加汇tt的最大流。
     19   这时候再添加弧<t,s>,下界为0,上界oo。
     20   在现在的这张图上,从ss到tt的最大流,就是原图的最小流。
     21   理解方法:
     22   我们前面提到过,有源汇可行流的流量只是对应一组可行流,并不是最大或者最小流。
     23   并且在跑完有源汇可行流之后,弧<t,s>的流量就是原图的流量。
     24   从这个角度入手,我们想让弧<t,s>的流量尽量小,就要尽量多的消耗掉那些“本来不需要经过<t,s>”的流量。
     25   于是我们在添加<t,s>之前,跑一遍从ss到tt的最大流,就能尽量多的消耗那些流量啦QwQ。
     26 */
     27 #include <bits/stdc++.h>
     28 using namespace std;
     29 typedef long long ll;
     30 const int LEN = 2e5 + 5;
     31 const int oo = (1LL << 31) - 1;
     32 namespace DINIC {
     33     int tot, n, m, src, tar, qh, qt, cnt, s, t, S, T, ans, flow;
     34     struct edge {
     35         int vet, next, len;
     36     } E[LEN * 2];
     37     int dis[LEN], gap[LEN], head[LEN], cur[LEN], q[LEN], vis[LEN], IN[LEN];
     38     void add(int u, int v, int c) {
     39         E[++tot] = (edge){v, head[u], c};
     40         head[u] = tot;
     41     }
     42     void join(int u, int v, int c) {
     43         add(u, v, c);
     44         add(v, u, 0);
     45     }
     46     void init() {
     47         tot = -1;
     48         for (int i = 1; i <= cnt; i++) head[i] = -1;
     49     }
     50     bool bfs() {
     51         for (int i = 1; i <= cnt; i++) dis[i] = 0;
     52         qh = qt = 0;
     53         q[++qt] = src;
     54         dis[src] = 1;
     55         while (qh < qt) {
     56             int u = q[++qh];
     57             for (int e = head[u]; e != -1; e = E[e].next) {
     58                 int v = E[e].vet;
     59                 if (E[e].len && !dis[v]) {
     60                     dis[v] = dis[u] + 1;
     61                     if (v == tar) return 1;
     62                     q[++qt] = v;
     63                 }
     64             }
     65         }
     66         return dis[tar];
     67     }
     68     int dfs(int u, int aug) {
     69         if (u == tar || !aug) return aug;
     70         int tmp = 0;
     71         for (int &e = cur[u]; e != -1; e = E[e].next) {
     72             int v = E[e].vet;
     73             if (dis[v] == dis[u] + 1) {
     74                 if (tmp = dfs(v, min(aug, E[e].len))) {
     75                     E[e].len -= tmp;
     76                     E[e ^ 1].len += tmp;
     77                     return tmp;
     78                 }
     79             }
     80         }
     81         return 0;
     82     }
     83     int maxflow(int s, int t) {
     84         src = s, tar = t;
     85         int res = 0, flow = 0;
     86         while (bfs()) {
     87             for (int i = 1; i <= cnt; i++) cur[i] = head[i];
     88             while (flow = dfs(src, oo)) res += flow;
     89         }
     90         return res;
     91     }
     92 }
     93 using namespace DINIC;
     94 int main() {
     95     scanf("%d %d %d %d", &n, &m, &s, &t);
     96     cnt = n;
     97     S = ++cnt, T = ++cnt;
     98     init();
     99     for (int i = 1; i <= m; i++) {
    100         int x, y, l, r;
    101         scanf("%d %d %d %d", &x, &y, &l, &r);
    102         join(x, y, r - l);
    103         IN[y] += l, IN[x] -= l;
    104     } 
    105     for (int i = 1; i <= n; i++) {
    106         if (IN[i] < 0) join(i, T, -IN[i]);
    107         else if (IN[i] > 0) {
    108             flow += IN[i];
    109             join(S, i, IN[i]);
    110         }
    111     }
    112     ans = maxflow(S, T);
    113     flow -= ans;
    114     join(t, s, oo);
    115     ans = maxflow(S, T);
    116     if (ans != flow) puts("please go home to sleep");
    117     else printf("%d
    ", ans);
    118     return 0;
    119 }
    有源汇最小流
  • 相关阅读:
    2.Android之按钮Button和编辑框EditText学习
    《DSP using MATLAB》Problem 3.8
    《DSP using MATLAB》Problem 3.7
    《DSP using MATLAB》Problem 3.6
    《DSP using MATLAB》Problem 3.5
    《DSP using MATLAB》Problem 3.4
    《DSP using MATLAB》Problem 3.3
    《DSP using MATLAB》Problem 3.2
    《DSP using MATLAB》Problem 3.1
    《DSP using MATLAB》Problem 2.20
  • 原文地址:https://www.cnblogs.com/NineSwords/p/9415962.html
Copyright © 2011-2022 走看看