zoukankan      html  css  js  c++  java
  • poj 1273 || hdu 1532 Drainage Ditches 最大流

    //poj 1273 || hdu 1532 Drainage Ditches 最大流

    //普通最大流

    //这里给出dinic的递归和非递归代码

    //非递归:
    //用dfs或bfs寻找一条增广路,并进行分层,比如 i能到 j,
    //则 j的层次比 i多 1。如果聚点有在 增广路上(即有对应的
    //层次,否则说明已经达到最大流了),然后顺着层次寻找一条
    //到达聚点的路,并记录下来,若某个结点流向下一结点时,流
    //用不完,则说明可能有分支,记录最后一个分支,若找到聚点
    //时停止查找。如果路径上最后一个结点为聚点时,计算能到达
    //聚点的流量,并建立反向边。之后从分支点找另一条能到聚点
    //的路。若路径上最后一个结点不是聚点时,跳向分支点前一个
    //结点找路,若一直找不到,直到源点时,继续dfs或bfs找增广路

    //递归:
    //bfs对残余网络分层,若到达不了sink则表示没有增广路了,
    //否则sink也分完层后就开始深搜从前一个节点到下
    //一个节点要有容量且下一个节点的层次要比前一节点多1才可继续深搜

    //非递归:记得保存分支的地方(上条边的流量流了一些到聚点后还有剩时);
    //注意用dinic的话如果用邻接表会tle,用邻接矩阵则不会。
    //dinic时,若深搜到的点不能到达sink的点的层次要标为 -1,
    //表示不能到达sink

    //具体看代码

    递归
    //递归
    #define comein freopen("in.txt", "r", stdin);
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    
    #define INF 1<<30
    #define N 500
    
    int eid, n_point;
    int map[N][N];      //用邻接表居然tle了
    int head[N], to[N], cap[N], next[N];
    int level[N];
    
    void add_edge(int from, int t, int f)
    {
        to[eid] = t;
        cap[eid] = f;
        next[eid] = head[from];
        head[from] = eid++;
    
        to[eid] = from;   //建反向边
        cap[eid] = 0;
        next[eid] = head[t];
        head[t] = eid++;
    }
    
    bool bfs(int root)     //残余网络分层
    {
        memset(level, -1, sizeof(level));
        queue<int>que;
        que.push(root);
        level[root] = 0;
        while(!que.empty())
        {
            root = que.front();
            que.pop();
    //        for(int i = head[root]; i != -1; i = next[i])
            for(int i = 1; i <= n_point; ++i)
            {   //边还有残余容量,且下一个点还没分层
                if(map[root][i] > 0 && level[i] == -1)
                {
                    level[i] = level[root] + 1;
                    if(i == n_point)
                        return true;
                    que.push(i);
                }
    //            if(level[to[i]] == -1 && cap[i])
    //            {
    //                level[to[i]] = level[root] + 1;
    //                if(to[i] == n_point)
    //                    return true;
    //                que.push(to[i]);
    //            }
            }
        }
        return false;
    }
    
    int dfs(int root, int f)
    {
        if(root == n_point)
            return f;
        int flow, ans = 0;
    //    for(int i = head[root]; i != -1; i = next[i])
        for(int i = 1; i <= n_point; ++i)
        {
    //        int m = min(cap[i], f - ans);   //记得这里要 f-ans
            int m = min(map[root][i], f-ans);
            if(map[root][i] > 0 && level[root] + 1 == level[i] &&
               ans < f && (flow = dfs(i, m) )   )
            {
                map[root][i] -= flow;
                map[i][root] += flow;
                ans += flow;
            }
    //        if(cap[i] && level[root]+1 == level[to[i]] && ans < f &&
    //           (flow = dfs(to[i], m ) )   )
    //        {   //下标从0开始,则正向边为偶数,反向边为基数;
    //            cap[i] -= flow;
    //            cap[i^1] += flow;//下标从1开始则不能用  异或
    //            ans += flow;
    //        }
        }
        if(ans == 0)    //若没找到增广路,这时注意要把该点
            level[root] = -1;   //的层次标为-1,表示不能到达
        return ans;
    }
    
    void dinic()
    {
        int flow = 0;
        while(bfs(1))  //分层
        {
            while(1)    //每条增广路都有一个瓶颈(增光路上最小容量的边)
            {   //每次分层都要把所有增广路的瓶颈都清除掉,再重新分层
                int f = dfs(1, INF);//因此最多层分v次
                if(f == 0)
                    break;
                flow += f;
            }
        }
        printf("%d\n", flow);
    }
    
    int main()
    {
        comein
        eid = 0;
    
        int n_edge;
        while(scanf("%d%d", &n_edge, &n_point) != EOF)
        {
            memset(map, 0, sizeof(map));
    //        memset(head, -1, sizeof(head));
            while(n_edge--)
            {
                int from, to, f;
                scanf("%d%d%d", &from, &to, &f);
                map[from][to] += f;
    //            add_edge(from, to, f);
            }
            dinic();
        }
        return 0;
    }
    非递归
    //Dinic    非递归
    //邻接矩阵
    #include <stdio.h>
    #include <string.h>
    #define N 205
    
    
    int n_node, n_edge;
    int map[N][N], level[N], que[N*N], path[N];
    
    int bfs(int s)
    {
        memset(level, -1, sizeof(level));
    
        int head = 0, tail = 0;
        que[tail++] = s;
        level[s] = 1;   //源点标记为第一层
    
        while(head < tail)
        {
            int now = que[head++];
            for(int i = 1; i <= n_node; ++i)
            {
                if(map[now][i] != 0 && level[i] == -1)
                {
                    level[i] = level[now] + 1;  //标记层数
                    que[tail++] = i;
                }
            }
        }
        //如果聚点没有被分层的话,说明已经达到最大流了
        return level[n_node] + 1;
    }
    
    int dinic(int s)
    {
        int max_flow = 0;
        while(bfs(s))    //广搜对一条增广路上的点分层
        {
            int  pos = 0, cut;
            path[++pos] = s;    //记录增广路
            while(1)
            {
                int flow = 1 << 30;
                int find = 1;
                //若增广路的最后一个结点是聚点,或者流不能流到下一个结点时,结束
                while(path[pos] != n_node && find)
                {
                    find = 0;
                    for(int i = 1; i <= n_node; ++i)
                    {
                        if(level[i] == level[path[pos]] + 1 && map[path[pos]][i] != 0)
                        {
                            find = 1;
                            path[++pos] = i;
                            break;
                        }
                    }
                }
                if(path[pos] == n_node) //若有找到增广路
                {
                    for(int i = 1; i < pos; ++i)
                    {
                        if(flow > map[path[i]][path[i+1]])
                        {
                            flow = map[path[i]][path[i+1]];
                            cut = i;    //记录分叉的地方,这个地方的流没全用完
                        }
                    }
                    max_flow += flow;
                    for(int i = 1; i < pos; ++i)
                    {
                        map[path[i]][path[i+1]] -= flow;
                        map[path[i+1]][path[i]] += flow;    //建反向边
                    }
                    pos = cut;  //从流没用完的边,也就是分支处继续找下一条到聚点的路
                }
                else    //若没有到达聚点
                {
                    if(pos == 1)
                        break;
                    else
                    {
                        level[path[pos]] = -1;  //若这个点不能到达聚点,则去掉
                        pos--;
                    }
                }
            }
        }
        return max_flow;
    }
    
    int main()
    {
        while(scanf("%d%d", &n_edge, &n_node) != EOF)
        {
            memset(map, 0, sizeof(map));
            for(int i = 0; i < n_edge; ++i)
            {
                int from, to, flow;
                scanf("%d%d%d", &from, &to, &flow);
                map[from][to] += flow;
            }
            printf("%d\n", dinic(1));
        }
        return 0;
    }
    EK算法
    //EK算法比较容易理解
    //用广搜找到一条增广路,记录路径,找出增广路中最小
    //的边为流到汇点的流量,建反向边,一直重复道没增广路为止;
    
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    
    using namespace std;
    
    #define INF (1<<30)
    #define N 205
    
    int map[N][N], fa[N];
    bool vis[N];
    
    bool bfs(int n) //广搜找增广路
    {
        memset(vis, false, sizeof(vis));
        memset(fa, -1, sizeof(fa));
        queue<int>que;
        que.push(1);
        vis[1] = true;
        while(!que.empty())
        {
            int now = que.front();
            que.pop();
            vis[now] = true;
            for(int i = 1; i <= n; ++i)
            {
                if(vis[i] == false && map[now][i] > 0)
                {
                    vis[i] = true;
                    fa[i] = now;    //记录路径
                    if(i == n)
                        return true;
                    que.push(i);
                }
            }
        }
        return false;
    }
    
    
    void EK(int n, int m)   //找增广路
    {
        int ans = 0;
        while(bfs(n))
        {
            int min = INF;
            //找出增广路的瓶颈,即增广路中的最短边
            for(int i = n; i != 1; i = fa[i])
                min = map[fa[i]][i] < min ? map[fa[i]][i] : min;
                
            for(int i = n; i != 1; i = fa[i])
            {
                map[fa[i]][i] -= min;
                map[i][fa[i]] += min;   //增加反向流
            }
            ans += min;
        }
        printf("%d\n", ans);
    }
    
    int main()
    {
        int n, m;
        while(scanf("%d%d", &m, &n) != EOF)
        {
            memset(map, 0, sizeof(map));
            for(int i = 0; i < m; ++i)
            {
                int from, to, f;
                scanf("%d%d%d", &from, &to, &f);
                map[from][to] += f;
            }
            EK(n, m);
        }
        return 0;
    }
  • 相关阅读:
    【codecombat】 试玩全攻略 第九关 循环又循环
    【codecombat】 试玩全攻略 第十三关 已知敌人
    【codecombat】 试玩全攻略 第十一关 再次迷宫经历
    【codecombat】 试玩全攻略 第六关 cell commentary
    【codecombat】 试玩全攻略 第八关 火舞
    【codecombat】 试玩全攻略 第十二关 恐惧之门
    【codecombat】 试玩全攻略 第十四关 已知敌人
    苹果apns推送总结
    Xcode 提升速度小技巧
    UITextField 限制输入字数
  • 原文地址:https://www.cnblogs.com/gabo/p/2623531.html
Copyright © 2011-2022 走看看