HDOJ 1532 Drainage Ditches (Ford-Fulkerson + EK + Dinic)


Drainage Ditches

Time Limit: 2000/1000 MS(Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 16953    Accepted Submission(s): 8019

Problem Description

Every time it rains on FarmerJohn's fields, a pond forms over Bessie's favorite clover patch. This meansthat the clover is covered by water for awhile and takes quite a long time toregrow. Thus, Farmer John has built a set of drainage ditches so that Bessie'sclover patch is never covered in water. Instead, the water is drained to anearby stream. Being an ace engineer, Farmer John has also installed regulatorsat the beginning of each ditch, so he can control at what rate water flows intothat ditch.
Farmer John knows not only how many gallons of water each ditch can transportper minute but also the exact layout of the ditches, which feed out of the pondand into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can betransported out of the pond and into the stream. For any given ditch, waterflows in only one direction, but there might be a way that water can flow in acircle.

 

 

Input

The input includes severalcases. 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 ditchesthat Farmer John has dug. M is the number of intersections points for thoseditches. Intersection 1 is the pond. Intersection point M is the stream. Eachof the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1<= Si, Ei <= M) designate the intersections between which this ditchflows. 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 singleinteger, 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


刚入门网络流,这里暂时先提供三种不同的解法


一:Ford-Fulkerson算法(算法复杂度约为O(V*E^2))

(注:本题V=200,E=200,时限为1s,还有一道类似的题V=15,E=1000,时限为5s)


#include<bits/stdc++.h>
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
#define maxn 205
#define INF 0x3f3f3f3f
#define mod 2009
using namespace std;
int pre[maxn],vis[maxn],mp[maxn][maxn];
int s,t,n,m;
bool bfs()  
{
    mst(vis,0);
    mst(pre,0);
    queue<int> q;
    vis[s]=1;
    q.push(s);
    while(q.size())
    {
        int cur=q.front();
        q.pop();
        if(cur==t) return 1;
        f(i,1,n)
        {
            if(!vis[i]&&mp[cur][i])
            {
                q.push(i);
                pre[i]=cur;
                vis[i]=1;
            }
        }
    }
    return 0;
}
int FF()
{
    int ans=0;
    while(1)
    {
        if(!bfs())
            return ans;
        int Min=INF;
        for(int i=t;i!=s;i=pre[i])
        {
            Min=min(Min,mp[pre[i]][i]);
        }
        for(int i=t;i!=s;i=pre[i])
        {
            mp[pre[i]][i]-=Min;
            mp[i][pre[i]]+=Min;
        }
        ans+=Min;
    }
}
int main()
{
    int u,v,w;
    while(~scanf("%d%d",&m,&n))
    {
        mst(mp,0);
        s=1,t=n;
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            mp[u][v]+=w;
        }
        printf("%d\n",FF());
    }
    return 0;
}


二:EK算法 (时间复杂度O(V*E^2),个人觉得算法本质与Ford-Fulkerson算法差不多)

#include<bits/stdc++.h>
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
#define maxn 205
#define INF 0x3f3f3f3f
#define mod 2009
using namespace std;
int c[maxn][maxn]; //记录残余网络的容量
int flow[maxn];    //记录从源点到当前节点实际剩余可用容量
int pre[maxn];     //记录此条路径当前节点的前驱,同时标记该节点是否在节点中,起到vis[]的作用
int s,t,n,m;
int bfs()
{
    queue<int> q;
    mst(pre,0xff);
    pre[s]=0;
    flow[s]=INF;
    q.push(s);
    while(q.size())
    {
        int cur=q.front();
        q.pop();
        if(cur==t)
            break;
        f(i,1,m)
        {
            if(c[cur][i]>0&&pre[i]==-1)
            {
                pre[i]=cur;
                flow[i]=min(flow[cur],c[cur][i]);
                q.push(i);
            }
        }
    }
    if(pre[t]==-1)
        return 0;
    return flow[t];
}
int EK()
{
    int add;
    int maxflow=0;
    while(bfs())
    {
        add=bfs();
        for(int i=t;i!=s;i=pre[i])
        {
            c[pre[i]][i]-=add;  //改变正向边的容量
            c[i][pre[i]]+=add;  //改变反向边的容量
        }
        maxflow+=add;
    }
    return maxflow;
}

int main()
{
    int u,v,w;
    while(~scanf("%d%d",&n,&m))
    {
        mst(c,0);
        mst(flow,0);
        s=1,t=m;
        while(n--)
        {
            scanf("%d%d%d",&u,&v,&w);
            c[u][v]+=w;
        }
        printf("%d\n",EK());
    }
    return 0;
}


三:Dinic算法(时间复杂度V^2*E,相对而言最高效)

推荐一个讲得比较好的博客: 传送门

#include<bits/stdc++.h>
#define mst(a,b) memset((a),(b),sizeof(a))
#define f(i,a,b) for(int i=(a);i<=(b);++i)
#define maxn 205
#define INF 0x3f3f3f3f
#define mod 2009
using namespace std;
int c[maxn][maxn];  //记录残余网络的容量
int dis[maxn];      //距源点距离,用于构造分层图
int n,m,s,t;
bool bfs()          //建立分层图(分层图是以当前图为基础建立的,所以要重复建立分层图)
{
    mst(dis,-1);
    queue<int> q;
    dis[s]=0;
    q.push(s);
    while(q.size())
    {
        int cur=q.front();
        q.pop();
        f(i,1,m)
        {
            if(dis[i]<0&&c[cur][i]>0)
            {
                dis[i]=dis[cur]+1;
                q.push(i);
            }
        }
    }
    if(dis[t]>0)
        return true;
    return false;
}
int find(int x,int low)     //代表一次增广,函数返回本次增广的流量,返回0表示无法增广
{
    int add;
    if(x==t)                //low是源点到现在最窄的(剩余流量最小)的边的剩余流量
        return low;
    f(i,1,m)
    {
        if(c[x][i]>0&&dis[i]==dis[x]+1&&(add=find(i,min(low,c[x][i]))))
        //两点联通&&当前点是前驱点分层图的下一层&&能到汇点
        {
            c[x][i]-=add;    //改变正向边的容量
            c[i][x]+=add;    //改变反向边的容量
            return add;
        }
    }
    return 0;
}

int main()
{
    int u,v,w;
    while(~scanf("%d%d",&n,&m))
    {
        mst(c,0);
        s=1,t=m;
        while(n--)
        {
            scanf("%d%d%d",&u,&v,&w);
            c[u][v]+=w;
        }
        int ans=0;
        int cnt;
        while(bfs())     //不停地建立分层图,直到BFS不到汇点
        {
            while(cnt=find(s,INF))    //一次BFS要不停地找增广路,直到找不到为止
                ans+=cnt;
        }
        printf("%d\n",ans);
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/my_sunshine26/article/details/70147227