首页 > 代码库 > [POJ 1273]Drainage Ditches(Edmond-Krap算法和Dinic算法求最大流)

[POJ 1273]Drainage Ditches(Edmond-Krap算法和Dinic算法求最大流)

自NOIP 2014结束之后将近一个星期没撸题了,现在开始搞省选,发个水水的裸网络流题解吧。

题目链接:http://poj.org/problem?id=1273

裸网络流,模板题。

1、Edmond_Karp算法

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <queue>

#define MAXV 220
#define MAXE 220
#define INF 0x3f3f3f3f

using namespace std;

int n,m;
int cap[MAXV][MAXV],flow[MAXV][MAXV]; //容量、流量
int a[MAXV];
int last[MAXV];

int EdmondsKarp(int s,int t) //EK算法求s到t的最大流
{
    int sum=0;
    queue<int>q;
    while(1)
    {
        while(!q.empty()) q.pop();
        q.push(s);
        memset(a,0,sizeof(a));
        a[s]=INF;
        while(!q.empty()) //找增广路
        {
            int u=q.front();
            q.pop();
            for(int v=1;v<=m;v++)
            {
                if(!a[v]&&flow[u][v]<cap[u][v])
                {
                    last[v]=u;
                    q.push(v);
                    a[v]=min(a[u],cap[u][v]-flow[u][v]);
                }
            }
        }
        if(a[t]==0) //找不到增广路,则已经找到最大流
            break;
        sum+=a[t]; //加上这次增广得到的流量
        for(int i=t;i!=s;i=last[i]) //根据增广路的链表顺着更新
        {
            flow[last[i]][i]+=a[t];
            flow[i][last[i]]-=a[t];
        }
    }
    return sum;
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(cap,0,sizeof(cap));
        memset(flow,0,sizeof(flow));
        for(int i=1;i<=n;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            cap[u][v]+=w;
        }
        printf("%d\n",EdmondsKarp(1,m));
    }
    return 0;
}
2、Dinic算法快速求网络流

#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#include <deque>
#include <cstring>

#define mem(array,num) memset(array,num,sizeof(array))
#define MAXE 300
#define INF 0x3f3f3f3f

using namespace std;

int G[MAXE][MAXE];
bool visit[MAXE];
int Layer[300]; //Layer[i]=点i所在层数
int n,m;

bool CountLayer() //BFS对图进行分层
{
    int layer=0;
    deque<int>q;
    mem(Layer,-1); //初始化所有层数都为-1
    Layer[1]=0; //点1层数为0
    q.push_back(1); //点1入队
    while(!q.empty())
    {
        int now=q.front();
        q.pop_front();
        for(int j=1;j<=m;j++)
        {
            if(G[now][j]>0&&Layer[j]==-1) //now->j有剩余容量且j还没被访问过
            {
                Layer[j]=Layer[now]+1;
                if(j==m) return true; //分层到达了汇点即可
                else q.push_back(j);
            }
        }
    }
    return false; //到达不了汇点,返回false
}

int Dinic()
{
    int i,s,maxFlow=0;
    deque<int>q; //栈,DFS用
    while(CountLayer()) //只要能分层
    {
        q.push_back(1); //源点入栈
        mem(visit,0);
        visit[1]=true;
        while(!q.empty())
        {
            int top=q.back();
            if(top==m) //top是汇点
            {
                int minC=INF; //在栈中找容量最小的边
                int SminC; //容量最小的边的起点
                for(int i=1;i<q.size();i++)
                {
                    int vs=q[i-1];
                    int ve=q[i];
                    if(G[vs][ve]>0)
                    {
                        if(minC>G[vs][ve]) //更新最小容量边
                        {
                            minC=G[vs][ve];
                            SminC=vs;
                        }
                    }
                }
                //增广,改图
                maxFlow+=minC;
                for(int i=1;i<q.size();i++)
                {
                    int vs=q[i-1];
                    int ve=q[i];
                    G[vs][ve]-=minC; //减少边容量
                    G[ve][vs]+=minC; //增加反向边
                }
                while(!q.empty()&&q.back()!=SminC) //退栈直到SminC成为栈顶,这样方便DFS
                {
                    visit[q.back()]=false;
                    q.pop_back();
                }
            }
            else //top不是汇点
            {
                int i;
                for(i=1;i<=m;i++)
                {
                    if(G[top][i]>0&&Layer[i]==Layer[top]+1&&!visit[i]) //只往下一层没有走过的节点走
                    {
                        visit[i]=1;
                        q.push_back(i);
                        break;
                    }
                }
                if(i>m) //找不到下一个点,则往回走
                    q.pop_back();
            }
        }
    }
    return maxFlow;
}

int main()
{
    while(cin>>n>>m) //n边m点
    {
        mem(G,0);
        for(int i=0;i<n;i++)
        {
            int u,v,c;
            cin>>u>>v>>c;
            G[u][v]+=c; //防止被坑,两点间可能有多条边,容量累加
        }
        cout<<Dinic()<<endl;
    }
    return 0;
}






[POJ 1273]Drainage Ditches(Edmond-Krap算法和Dinic算法求最大流)