zoukankan      html  css  js  c++  java
  • 最大流 Dinic算法

    Ford-Fulkerson算法是通过深度优先搜索寻找增广路,并沿着它增广。

    与之相对,Dinic算法总是寻找最短的增广路,并沿着它增广。因为最短增广路的长度在增广过程中始终不会变短,所以无需每次都通过宽度预先搜索来寻找最短增广路。

    我们可以先进行一次宽度优先搜索,然后考虑由进距离顶点指向远距离顶点的边所组成的分层图,在上面进行深度优先搜索寻找最短增广路。

    如果在分层图上找不到新的增广路,则说明最短增长路的长度确实边长了,或不存在增广路,于是重新通过宽度优先搜索构造新的分层图。每一步构造分层图的复杂度为O(|E|),而每一步完成之后最短增广路的长度都会至少增加1,由于增广路的长度不会超过|V|-1,因此最多重复O(|V|)步就可以了。

    另外,在每次对分层图进行宽度优先搜索寻找增广路时,如果避免对一条没有用的边进行多次查找,就可以保证复杂度为O(|E||V|),这样总的复杂度就是O(|E||V|^2)。

    HDU1532为例,这题用Ford-Fulkerson算法会超时,而用Dinic算法就不会。

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #include <vector>
     5 #include <queue>
     6 #define INF 0x3f3f3f3f
     7 using namespace std;
     8 const int MAX = 220;
     9 int n, m;
    10 struct Nod {
    11     int to, cap, rev;
    12 };
    13 vector<Nod> G[MAX];
    14 int level[MAX], iter[MAX];
    15 void add_edge(int from, int to, int cap) {
    16     G[from].push_back((Nod){to,cap,(int)G[to].size()});
    17     G[to].push_back((Nod){from,0,(int)G[from].size()-1});
    18 }
    19 void bfs(int s) {
    20     memset(level, -1, sizeof(level));
    21     queue<int> que;
    22     level[s] = 0;
    23     que.push(s);
    24     while(!que.empty()) {
    25         int v = que.front(); que.pop();
    26         for(int i = 0; i < G[v].size(); i ++) {
    27             Nod &e = G[v][i];
    28             if(e.cap > 0 && level[e.to] < 0){
    29                 level[e.to] = level[v] + 1;
    30                 que.push(e.to);
    31             }
    32         }
    33     }
    34 }
    35 int dfs(int v, int t, int f) {
    36     if(v == t) return f;
    37     for(int &i = iter[v]; i < G[v].size(); i ++) {
    38         Nod &e = G[v][i];
    39         if(e.cap > 0 && level[v] < level[e.to]) {
    40             int d = dfs(e.to, t, min(f,e.cap));
    41             if(d > 0) {
    42                 e.cap -= d;
    43                 G[e.to][e.rev].cap += d;
    44                 return d;
    45             }
    46         }
    47     }
    48     return 0;
    49 }
    50 int max_flow(int s, int t) {
    51     int flow = 0;
    52     while(1) {
    53         bfs(s);
    54         if(level[t] < 0) return flow;
    55         memset(iter,0,sizeof(iter));
    56         int f;
    57         while((f = dfs(s, t, INF)) > 0) flow += f;
    58     }
    59 }
    60 int main() {
    61     while(scanf("%d %d",&n, &m) != EOF) {
    62         for(int i = 0; i < n; i ++) {
    63             int u, v, w;
    64             scanf("%d %d %d",&u, &v, &w);
    65             add_edge(u, v, w);
    66         }
    67         printf("%d
    ",max_flow(1,m));
    68         for(int i = 0; i <= m; i ++) G[i].clear();
    69     }
    70     return 0;
    71 }
  • 相关阅读:
    给TextView添加超链接的四种方式
    详解ExplosionField的使用,实现View的粉碎效果
    SpannableString使用详解
    android开发之wheel控件使用详解
    使用HttpURLConnection实现在android客户端和服务器之间传递对象
    关于Fragment与Fragment、Activity通信的四种方式
    Volley完全解析
    ListView异步加载图片,完美实现图文混排
    使用DrawerLayout实现QQ5.0侧拉菜单效果
    使用DrawerLayout实现侧拉菜单
  • 原文地址:https://www.cnblogs.com/xingkongyihao/p/7265242.html
Copyright © 2011-2022 走看看