HDU 1532 Drainage Ditches 最大流

一、地址

  • 题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1532
  • GitHub:https://github.com/lamborghini1993/ACMTopic

二、题意

  • 有N条排水沟,有M个池塘,接下来N条排水沟,其中从Si池塘->Ei池塘的这条排水沟的容量为Ci。
  • 从1号池塘开始(水无限),问到M号池塘同时可以有多大的流量。

三、解题思路:

1.分析

  • 就是在容量容许的条件下,从源点到汇点所能通过的最大流量。
  • 实际上就是一个最大流问题。

2.最大流

​ 网络流G=(v, E)是一个有向图,其中每条边(u, v)均有一个非负的容量值,记为c(u, v) ≧ 0。如果(u, v) ∉ E则可以规定c(u, v) = 0。网络流中有两个特殊的顶点,即源点s和汇点t。

与网络流相关的一个概念是流。设G是一个流网络,其容量为c。设s为网络的源点,t为汇点,那么G的流是一个函数f:V×V →R,满足一下性质:
容量限制:对所有顶点对u,v∈V,满足f(u, v) ≦ c(u, v);
反对称性:对所有顶点对u,v∈V,满足f(u, v) = - f(v, u);
流守恒性:对所有顶点对u∈V-{s, t},满足Σv∈Vf(u,v)=0。

​ 本文开始讨论解决最大流问题的Ford-Fulkerson方法,该方法也称作“扩充路径方法”,该方法是大量算法的基础,有多种实现方法。

Ford-Fulkerson算法是一种迭代算法,首先对图中所有顶点对的流大小清零,此时的网络流大小也为0。在每次迭代中,通过寻找一条“增广路径”(augument path)来增加流的值。增广路径可以看作是源点s到汇点t的一条路径,并且沿着这条路径可以增加更多的流。迭代直至无法再找到增广路径位置,此时必然从源点到汇点的所有路径中都至少有一条边的满边(即边的流的大小等于边的容量大小)。

最大流最小割定理:一个网中所有流中的最大值等于所有割中的最小容量。

3.寻找增广路径方法的影响

​ 增广路径事实上是残留网中从源点s到汇点t的路径,可以利用图算法中的任意一种被算法来获取这条路径,例如BFS,DFS等。其中基于BFS的算法通常称为Edmonds-Karp算法,该算法是“最短”扩充路径,这里的“最短”由路径上的边的数量来度量,而不是流量或者容量。

​ 所以BFS增广效率比DFS效率高。

四、AC代码

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int N = 210;
int edge[N][N], pre[N];
bool visit[N];
int m, n, si, ei, ci, result, p, i;

bool BFS(int s, int t)
{
    memset(visit, false, sizeof(visit));
    memset(pre, -1, sizeof(pre));
    queue<int> q;
    q.push(s);
    visit[s] = true;
    pre[s] = s;
    while(!q.empty())
    {
        p = q.front();
        q.pop();
        for(i = 1; i <= m; i++)
        {
            if(visit[i] || edge[p][i] <= 0)
                continue;
            visit[i] = true;
            pre[i] = p;
            if(i == t)return true;
            q.push(i);
        }
    }
    return false;
}

int main()
{
    while(scanf("%d %d", &n, &m) != EOF)
    {
        result = 0;
        memset(edge, 0, sizeof(edge));
        while(n--)
        {
            scanf("%d %d %d", &si, &ei, &ci);
            edge[si][ei] += ci;//注意重边
        }
        while(BFS(1, m))
        {
            int end = m, start, minF = INT_MAX;
            for(end = m; end != 1; end=start)
            {
                start = pre[end];
                minF = min(minF, edge[start][end]);
            }
            for(end = m; end != 1; end = start)
            {
                start = pre[end];
                edge[start][end] -= minF;
                edge[end][start] += minF;
            }
            result += minF;
        }
        printf("%d\n", result);
    }
    return 0;
}

你可能感兴趣的:(☀,ACM成长之路,HDU,1532,最大流,Drainage,Ditches)