POJ - 1273 Drainage Ditches(最大流Dinic算法)

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\n",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\n",dinic());
    }
}
**/

猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/80518431