zoukankan      html  css  js  c++  java
  • POJ

    Every time it rains on Farmer John’s fields, a pond forms over Bessie’s favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie’s clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
    Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
    Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.
    Input
    The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.
    Output
    For each case, output a single integer, the maximum rate at which water may emptied from the pond.
    Sample Input
    5 4
    1 2 40
    1 4 20
    2 4 20
    2 3 30
    3 4 10
    Sample Output
    50

    最大流入门题:给出n条边,m个点,给出每条边的流量,求结点1到n的最大流。
    EK算法可以说是复杂度最大的最大流算法了,通过广搜找增广路,然后记录找到的一条增广路的路径,即记录路径上节点的fa,以便回溯时更新图上被减小的正向流量和被增加的反向边。

    用vector构造链式前向星是真的方便,除非遇到专门卡vector的题,否则都不会用数组模拟的链式前向星了。

    而对于dinic算法,相比EK算法多了个分层图的概念,将图广搜分层,目的是为了实现一次搜索多次増广,且不出现回头路的死循环。这是非常巧妙的,想想一次广搜即可分层,一次深搜即可得到该分层图上所有流,这就是多次増广的效率。可以说是裸的网络流算法中最快的一种了。还没有加上炸点等优化。复杂度还是可接受的

    #include<stdio.h>
    #include<queue>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    const int maxn=208;
    const int inf=0x3f3f3f3f;
    struct edge///vector链式前向星
    {
        int to,val,rev;
        edge(){}
        edge(int a,int b,int c)
        {
            to=a;
            val=b;
            rev=c;
        }
    };
    int n,m,dep[maxn];
    vector<edge>mp[maxn];
    void add(int from,int to,int val)///加边
    {
        mp[from].push_back(edge(to,val,mp[to].size()));
        mp[to].push_back(edge(from,0,mp[from].size()-1));
    }
    int bfs()
    {
        memset(dep,-1,sizeof dep);
        queue<int>q;
        while(!q.empty())q.pop();
        dep[1]=0;
        q.push(1);
        while(!q.empty())
        {
            int tmp=q.front();
            q.pop();
            if(tmp==n) return 1;
            for(int i=0;i<mp[tmp].size();i++)
            {
                int &to=mp[tmp][i].to,flow=mp[tmp][i].val;
                if(dep[to]==-1&&flow)
                {
                    dep[to]=dep[tmp]+1;
                    q.push(to);
                }
            }
        }
        return 0;
    }
    int dfs(int s,int t,int flow)
    {
        if(s==t)return flow;
        int pre=0;
        for(int i=0;i<mp[s].size();i++)
        {
            int &to=mp[s][i].to,val=mp[s][i].val;
            if(dep[s]+1==dep[to]&&val>0)
            {
                int tmp=min(flow-pre,val);
                int sub=dfs(to,t,tmp);
                mp[s][i].val-=sub;
                mp[to][mp[s][i].rev].val+=sub;
                pre+=sub;
                if(pre==flow)return pre;
            }
        }
        return pre;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())ans+=dfs(1,n,inf);
        return ans;
    }
    int main()
    {
        int from,to,val;
        while(scanf("%d%d",&m,&n)!=EOF)
        {
            for(int i=0;i<=n;i++)mp[i].clear();
            for(int i=0;i<m;i++)
            {
                scanf("%d%d%d",&from,&to,&val);
                add(from,to,val);
            }
            printf("%d
    ",dinic());
        }
    }
    
    

    以下是利用链式前向星存边,其实和vector一样,只是数组模拟而已:

    /**
    #include<stdio.h>
    #include<queue>
    #include<algorithm>
    #include<string.h>
    using namespace std;
    const int maxn=208;
    const int inf=0x3f3f3f3f;
    struct edge///链式前向星
    {
        int next,to,val;
    }mp[maxn*maxn];
    int head[maxn],dep[maxn],cnt;
    int n,m;
    void add(int from,int to,int val)///加边
    {
        mp[cnt].to=to,mp[cnt].val=val;
        mp[cnt].next=head[from],head[from]=cnt++;
        mp[cnt].to=from,mp[cnt].val=0;
        mp[cnt].next=head[to],head[to]=cnt++;
    }
    int bfs()
    {
        memset(dep,-1,sizeof dep);
        queue<int>q;
        while(!q.empty())q.pop();
        dep[1]=0;
        q.push(1);
        while(!q.empty())
        {
            int tmp=q.front();
            q.pop();
            if(tmp==n) return 1;
            for(int i=head[tmp];i!=-1;i=mp[i].next)
            {
                int &to=mp[i].to,flow=mp[i].val;
                if(dep[to]==-1&&flow)
                {
                    dep[to]=dep[tmp]+1;
                    q.push(to);
                }
            }
        }
        return 0;
    }
    int dfs(int s,int t,int flow)
    {
        if(s==t)return flow;
        int pre=0;
        for(int i=head[s];i!=-1;i=mp[i].next)
        {
            int &to=mp[i].to,val=mp[i].val;
            if(dep[s]+1==dep[to]&&val>0)
            {
                int tmp=min(flow-pre,val);
                int sub=dfs(to,t,tmp);
                mp[i].val-=sub;
                mp[i^1].val+=sub;
                pre+=sub;
                if(pre==flow)return pre;
            }
        }
        return pre;
    }
    int dinic()
    {
        int ans=0;
        while(bfs())ans+=dfs(1,n,inf);
        return ans;
    }
    int main()
    {
        int from,to,val;
        while(scanf("%d%d",&m,&n)!=EOF)
        {
            cnt=0;
            memset(head,-1,sizeof head);
            for(int i=0;i<m;i++)
            {
                scanf("%d%d%d",&from,&to,&val);
                add(from,to,val);
            }
            printf("%d
    ",dinic());
        }
    }
    **/
    
  • 相关阅读:
    ASP.NET Forms 身份验证概述
    JS中变量相关的细节分析
    document对象execCommand的命令参数介绍
    一点一点学ASP.NET之基础概念——HTTP运行期与页面执行模型
    读《大道至简》第一章有感
    读大道至简第二章有感
    课程作业2
    编写一个程序,用户输入两个数,求其加减乘除,并用消息框显示计算结果。
    201920201 20209324《Linux内核原理与分析》第一周作业
    jQuery Plugins
  • 原文地址:https://www.cnblogs.com/kuronekonano/p/11135766.html
Copyright © 2011-2022 走看看