网络流

来源:互联网 发布:域名网 编辑:程序博客网 时间:2024/06/16 07:41

网络流专题:点击打开链接


一、最大流之增广路算法

这个博客讲解放入挺详细的:点击打开链接

前向弧:离开点u的有向弧

后向弧:进入点u的有向弧

【恩~有一点我觉得有必要记录一下】

建立这些后向弧的必要性:


如果不建立后向边就容易出现上面这种情况,结果会偏小,路径是:1->2->5、1->2->3->5、1->3->5。

建立后向边之后,路径会增加一条:1->2->5、1->2->3->5、1->3->2->4->5、1->3->5。

2->3流量是1,3->2流量是1,相当于就没有流过。

模板题:【hdu 1532】

1、EdmondsKarp

struct Edge {int from, to, cap, flow;Edge(int u, int v, int c, int f):from(u),to(v),cap(c),flow(f){}}; struct EdmondsKarp {int n, m;vector<Edge> edges;vector<int> G[maxn];int a[maxn];int p[maxn];void init(int n) {for(int i=0; i<n; i++) G[i].clear();edges.clear();}void AddEdge(int from, int to, int cap) {edges.push_back(Edge(from, to, cap, 0));edges.push_back(Edge(to, from, 0, 0));//反向弧m  = edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}int Maxflow(int s, int t) {int flow = 0;for(;;){memset(a, 0, sizeof(a));queue<int>Q;Q.push(s);a[s] = INF;while(!Q.empty()) {int x = Q.front(); Q.pop();int len = (int)G[x].size();for(int i=0; i<len; i++) {Edge& e = edges[G[x][i]];if(!a[e.to] && e.cap>e.flow) {p[e.to] = G[x][i];a[e.to] = min(a[x], e.cap-e.flow);Q.push(e.to);}}if(a[t]) break;}if(!a[t]) break;for(int u = t; u!=s; u=edges[p[u]].from) {edges[p[u]].flow += a[t];edges[p[u]^1].flow -= a[t];}flow += a[t];}return flow;}};



2、Dinic递归:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>#include <vector>#include <queue>using namespace std;const int maxn=1e3+10;const int INF = 0x3f3f3f3f;struct Edge {int from, to, cap, flow;Edge(int u, int v, int c, int f):from(u),to(v),cap(c),flow(f){}}; vector<Edge> edges;vector<int>G[maxn];bool vis[maxn];int dis[maxn];int cur[maxn];void init(int n) {for(int i=0; i<n; i++) G[i].clear();edges.clear();}void AddEdge(int from, int to, int cap) {edges.push_back(Edge(from, to, cap, 0));edges.push_back(Edge(to, from, 0, 0));//反向弧int m  = edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}bool BFS(int s, int t) {memset(vis, 0, sizeof(vis));int n, m;queue<int> Q;Q.push(s);dis[s] = 0;vis[s] = 1;while(!Q.empty()) {int x = Q.front(); Q.pop();for(int i = 0; i < G[x].size(); i++) {Edge& e = edges[G[x][i]];if(!vis[e.to] && e.cap > e.flow) {vis[e.to] = 1;dis[e.to] = dis[x] + 1;Q.push(e.to);}}}return vis[t];}int DFS(int x, int t, int a){if(x == t || a == 0) return a;int flow = 0, f;for(int& i = cur[x]; i < G[x].size(); i++) {Edge& e = edges[G[x][i]];if(dis[x] + 1 == dis[e.to] && (f = DFS(e.to, t, min(a, e.cap-e.flow))) > 0) {e.flow += f;edges[G[x][i]^1].flow -= f;flow += f;a -= f;if(a == 0) break;}}return flow;}int Maxflow(int s, int t){int flow = 0;while(BFS(s, t)) {memset(cur, 0, sizeof(cur));flow += DFS(s, t, INF);}return flow;}int main(){int m, n;while(~scanf("%d%d", &m, &n)) {init(n);for(int i=0; i<m; i++){int u, v, c;scanf("%d%d%d", &u, &v, &c);AddEdge(u, v, c);}printf("%d\n", Maxflow(1, n));}return 0;}


3、Dinic非递归:

#include <cstdio>  #include <cstring>  #include <algorithm>  #include <iostream>  using namespace std;  //点标 [0,n]  const int N = 200010;  const int M = 500010;  const int INF = ~0u >> 2;  template<class T>  struct Max_Flow {      int n;      int Q[N], sign;      int head[N], level[N], cur[N], pre[N];      int nxt[M], pnt[M], E;      T cap[M];      void Init(int n) {          this->n = n+1;          E = 0;          std::fill(head, head + this->n, -1);      }      //有向rw 就= 0       void add(int from, int to, T c, T rw) {          pnt[E] = to;          cap[E] = c;          nxt[E] = head[from];          head[from] = E++;            pnt[E] = from;          cap[E] = rw;          nxt[E] = head[to];          head[to] = E++;      }      bool Bfs(int s, int t) {          sign = t;          std::fill(level, level + n, -1);          int *front = Q, *tail = Q;          *tail++ = t; level[t] = 0;          while(front < tail && level[s] == -1) {              int u = *front++;              for(int e = head[u]; e != -1; e = nxt[e]) {                  if(cap[e ^ 1] > 0 && level[pnt[e]] < 0) {                      level[pnt[e]] = level[u] + 1;                      *tail ++ = pnt[e];                  }              }          }          return level[s] != -1;      }      void Push(int t, T &flow) {          T mi = INF;          int p = pre[t];          for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {              mi = std::min(mi, cap[p]);          }          for(int p = pre[t]; p != -1; p = pre[pnt[p ^ 1]]) {              cap[p] -= mi;              if(!cap[p]) {                  sign = pnt[p ^ 1];              }              cap[p ^ 1] += mi;          }          flow += mi;      }      void Dfs(int u, int t, T &flow) {          if(u == t) {              Push(t, flow);              return ;          }          for(int &e = cur[u]; e != -1; e = nxt[e]) {              if(cap[e] > 0 && level[u] - 1 == level[pnt[e]]) {                  pre[pnt[e]] = e;                  Dfs(pnt[e], t, flow);                  if(level[sign] > level[u]) {                      return ;                  }                  sign = t;              }          }      }      T Dinic(int s, int t) {          pre[s] = -1;          T flow = 0;          while(Bfs(s, t)) {              std::copy(head, head + n, cur);              Dfs(s, t, flow);          }          return flow;      }  };  Max_Flow <int>F;  int main(){      int t, n, m;scanf("%d", &t);      while(t--) {      scanf("%d%d", &n, &m);        F.Init(n);          int s = 1, t = n;        for(int i=0; i<m; i++){              int u, v, c;              scanf("%d%d%d", &u, &v, &c);              F.add(u, v, c, c);          }          printf("%d\n", F.Dinic(s, t));      }      return 0;  }  

【HDU 4280】 Island Transport 用Dinic非递归做能对,递归超时



易错例题:

A、【POJ 3281 Dining】

有n头牛,f中食物,d种饮料,每头牛都只吃固定的几种食物跟饮料,问最多有几头牛能吃到一种食物,一种饮料

注意点就是建图的时候n个点要拆成2*n个点,免得一头牛吃了多食物跟饮料。


二、最小割最大流

三、最小费用最大流

和Edmonds-Karp类似,但每次用Bellman-Ford算法而非BFS找增广路。

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <string>#include <vector>#include <queue>#include <map>using namespace std;const int maxn=1e3+10;const int INF = 0x3f3f3f3f;struct Edge {int from, to, cap, flow, cost;Edge(int u, int v, int c, int f, int w):from(u), to(v), cap(c), flow(f), cost(w){}};vector<Edge> edges;vector<int> G[maxn];int inq[maxn];int d[maxn];int p[maxn];int a[maxn];void init(){for(int i=0; i<maxn; i++) G[i].clear();edges.clear();}void AddEdge(int from, int to, int cap, int cost) {edges.push_back(Edge(from, to, cap, 0, cost));edges.push_back(Edge(to, from, 0, 0, -cost));int m = edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}bool BellmanFord(int s, int t, int& flow, long long& cost) {memset(inq, 0, sizeof(inq));memset(d, INF, sizeof(d));d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;queue<int>Q;Q.push(s);while(!Q.empty()) {int u = Q.front(); Q.pop();inq[u] = 0;for(int i = 0; i < G[u].size(); i++) {Edge& e = edges[G[u][i]];if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {d[e.to] = d[u] + e.cost;p[e.to] = G[u][i];a[e.to] = min(a[u], e.cap - e.flow);if(!inq[e.to]){Q.push(e.to);inq[e.to] = 1;}}}}if(d[t] == INF) return false;flow += a[t];cost += (long long)d[t] * (long long)a[t];for(int u = t; u != s; u = edges[p[u]].from) {edges[p[u]].flow += a[t];edges[p[u]^1].flow -= a[t];}return true;}//需要保证初始网络中没有负权圈int MincostMaxflow(int s, int t, long long& cost) {int flow = 0;cost = 0;while(BellmanFord(s, t, flow, cost));return flow;}int main() {int n, m;while(~scanf("%d%d", &n, &m)){init();for(int i=0; i<m; i++){int u, v, f, c;scanf("%d%d%d%d", &u, &v, &f, &c);AddEdge(u, v, f, c);}long long cost=0;int flow = MincostMaxflow(1, n, cost);printf("%d %lld\n", flow, cost);}return 0;} 





0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 没有带护理液了怎么办 护理液忘记带了怎么办 康宁玻璃锅裂了怎么办 带隐形牙套喝酒怎么办 牙齿保持器丢了怎么办 牙套保持器坏了怎么办 牙齿磕掉了一小块怎么办 牙齿裂掉了一半怎么办 大牙缺了一小块怎么办 牙根碎了一小块怎么办 门牙碎了一小块怎么办 孩子门牙长歪了怎么办 儿童门牙长歪了怎么办 大门牙长歪了怎么办 下面牙齿长歪了怎么办 只有一颗牙齿歪怎么办 牙齿突然长歪了怎么办 有个牙齿长歪了怎么办 一颗大牙长歪了怎么办 一颗牙齿长偏了怎么办 一个门牙长歪了怎么办 儿童牙齿长歪了怎么办 孩子牙齿长歪了怎么办 宝宝门牙长歪了怎么办 一颗牙齿挤歪了怎么办 后槽牙掉了一块怎么办 最里面的牙掉了怎么办 成年了牙齿掉了怎么办 我的门牙豁牙子怎么办 小孩牙齿长得稀怎么办 后槽牙掉了一颗怎么办 前门牙掉了一颗怎么办 牙齿黄怎么办小苏打美白牙齿 1岁宝宝牙齿发黄怎么办 宝宝一岁牙齿黄怎么办 宝宝出的牙黄怎么办 我的牙齿很黄怎么办 小孩换的牙发黄怎么办 换牙后牙齿变黄怎么办 抽烟让牙齿变黄怎么办 抽烟把牙齿抽黄了怎么办