Drainage Ditches(网络流入门)

推荐博客:
网络流

一:网络流的各种定义:
网络流(network-flows):
是一种类比水流的解决问题方法,与线性规划密切相关。

好比你家是 汇
自来水厂是 源
然后自来水厂和你家之间修了很多条水管子接在一起 水管子规格不一 有的容量大 有的容量小
然后问自来水厂开闸放水 你家收到水的最大流量是多少(各个管子的流量加和)
如果自来水厂停水了 你家那的流量就是0 当然不是最大的流量
但是你给自来水厂交了100w美金 自来水厂拼命水管里通水
但是你家的流量也就那么多不变了(每个水管都达到了最大的流速,不可能再大了) 这时就达到了最大流
二:性质
对于任意一个时刻,设f(u,v)实际流量,则整个图G的流网络满足3个性质:

  1. 容量限制:对任意u,v∈V,f(u,v)≤c(u,v)。
    每个水管里面的流量( f )都会小于水管的最大容量(c)。

  2. 反对称性:对任意u,v∈V,f(u,v) = -f(v,u)。从u到v的流量一定是从v到u的流量的相反值。
    也就是说,这个水管里水是有方向的。

  3. 流守恒性:对任意u,若u不为S或T,一定有∑f(u,v)=0,(u,v)∈E。即u到相邻节点的流量之和为0,因为流入u的流量和u点流出的流量相等,u点本身不会”制造”和”消耗”流量。
    除了你家和自来水厂,其余所有节点,流入的水=流出的水。


    例题

    Drainage Ditches
    Time Limit: 1000MS Memory Limit: 10000K
    Total Submissions: 83006 Accepted: 32249
    Description

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
Source

USACO 93

/*
* ff算法
* 复杂度O(F|E|)//F为最大流量
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 123123;
#define INF  0x3f3f3f3f
struct edge//边的结构体
{
    int to, cap, rev;//到达的点,边的容量,反向边
};
vector <edge> G[MAX];//二维
bool used[MAX];//dfs的时候标记是否被访问过
void add_edge(int from, int to, int cap)//建边
{
    struct edge a;
    //正向建立
    a.to = to;
    a.cap = cap;
    a.rev = G[to].size();
    G[from].push_back(a);
    //反向建立,反向边
    a.to = from;
    a.cap = 0;
    a.rev = G[from].size()-1;//对应正向边。
    G[to].push_back(a);
}
int dfs(int v, int t, int f)//寻找从v到t的最大流量
{
    if(v==t)//找到终点,返回这条路径上的最大流
        return f;
    used[v] = true;//标记访问过
    for(int i=0; i<G[v].size(); i++)//遍历从v出发的每一条边
    {
        edge &e = G[v][i];//找到这个边
        if(!used[e.to]&&e.cap>0)//如果到达的点没有被访问过,并且这条边还可以流水,有容量
        {
            int d = dfs(e.to, t, min(f, e.cap));//继续dfs,注意最大流量是min(此条边的容量,之前的最小的容量)
            if(d>0)//如果存在这条边
            {
                e.cap -= d;//将容量减少
                G[e.to][e.rev].cap += d;//反向边的容量增加
                return d;//返回最大流量
            }
        }
    }
    return 0;//否则0
}
int max_flow(int s, int t)
{
    int flow = 0;//记录要输出的最大流量
    for(;;)
    {
        memset(used, 0, sizeof(used));//标记值清空
        int f = dfs(s, t, INF);//找到此时存在的一条边的最大流量
        if(f==0)//此时说明已经没有符合的条件了
            return flow;//返回最大流量
        flow += f;//继续加。。
    }
}
int main()
{
    int n, m;
    while(~scanf("%d %d", &n, &m))
    {
        for(int i=0;i<m;i++)
        {
            G[i].clear();//注意清
        }
        for(int i=0; i<n; i++)
        {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            add_edge(a, b, c);
        }
        int w = max_flow(1, m);//寻找从1到m的最大流量。
        printf("%d\n", w);
    }
    return 0;
}
/* Dinic 算法
* 复杂度 O(|E||V|^2)
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#define MAX 123123
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
    int to, cap, rev;//终点,容量,反向边
};
vector <edge> G[MAX];
int level[MAX];
int iter[MAX];//记录当前的弧,之前的弧已经没有用了
void add_edge(int from, int to, int cap)
{
    edge a;
    a.to = to;
    a.cap = cap;
    a.rev = G[to].size();
    G[from].push_back(a);
    a.to = from;
    a.cap = 0;
    a.rev = G[from].size()-1;
    G[to].push_back(a);
}
//通过bfs计算从源点出发的距离的标号
void bfs(int s)
{
    memset(level, -1, sizeof(level));
    queue<int> que;
    level[s] = 0;
    que.push(s);
    while(!que.empty())
    {
        int v = que.front();
        que.pop();
        for(int i=0;i<G[v].size();i++)
        {
            edge &e = G[v][i];
            if(e.cap>0&&level[e.to]<0)
            {
                level[e.to] = level[v]+1;
                que.push(e.to);
            }
        }
    }
}
//通过dfs寻找增广路
int dfs(int v, int t, int f)//源点 汇点 流量
{
    if(v==t)
        return f;
    for(int &i = iter[v];i<G[v].size();i++)//算是优化
    {
        edge & e = G[v][i];
        if(e.cap>0&&level[v]<level[e.to])
        {
            int d = dfs(e.to, t, min(f, e.cap));
            if(d>0)
            {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s, int t)//寻找从s到t的最大流
{
    int flow = 0;
    for(;;)
    {
       bfs(s);//标记每个点的level
       if(level[t]<0)//s到t不连通
        return flow;
       memset(iter, 0, sizeof(iter));//当前弧清零
       int f;
       while((f=dfs(s, t, INF))>0)//不断寻找增广路,如果返回的流量大于0
       {
           flow += f;//符合要求,加入流量
       }
    }
}
int main()
{
    int n, m;
    while(~scanf("%d %d", &n, &m))
    {
        for(int i=0;i<m;i++)
        {
            G[i].clear();
        }
        for(int i=0;i<n;i++)
        {
            int a, b, c;
            scanf("%d %d %d", &a, &b, &c);
            add_edge(a, b, c);
        }
        int w = max_flow(1, m);
        printf("%d\n", w);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/feather2016/article/details/80284085