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 }
    有源汇最小流
  • 相关阅读:
    Python基础03 序列
    Python基础04 运算
    Python基础01 Hello World!
    Python基础02 基本数据类型
    wpf 中AxShockwaveFlash重写以及屏蔽鼠标右键
    正则表达式判断金额
    解决jquery操作checkbox全选全不选无法勾选问题
    关于asp.net网址出现乱码问题的解决方法
    c#中用DirectShow实现媒体播放器的核心(1) DirectShow简介
    “XXX.Index”不扩展类“System.Web.UI.Page”,因此此处不允许的问题
  • 原文地址:https://www.cnblogs.com/NineSwords/p/9415962.html
Copyright © 2011-2022 走看看