Live2D
博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

P3376 【模板】网络最大流

网络流

一、概念


网络流用于解决流量问题

网络流:所有弧上流量的集合f={f(u,v)},称为该容量网络的一个网络流。

1、定义:带权的有向图G=(V,E),满足以下条件,则称为网络流图(flow network):

  1. 仅有一个入度为0的顶点s,称s为源点。
  2. 仅有一个出度为0的顶点t,称t为汇点。
  3. 每条边的权值都为非负数,称为该边的容量,记作c(i,j)。

2、弧的流量:通过容量网络G中每条弧< u,v>,上的实际流量(简称流量),记为f(u,v)。

3、可行流:在容量网络G中满足以下条件的网络流f,称为可行流。

a.弧流量限制条件:   0<=f(u,v)<=c(u,v);

b:平衡条件:即流入一个点的流量要等于流出这个点的流量,(源点和汇点除外).

4、零流 若网络流上每条弧上的流量都为0,则该网络流称为零流。 

5、伪流:如果一个网络流只满足弧流量限制条件,不满足平衡条件,则这种网络流为伪流,或称为容量可行流.(预流推进算法有用)。

6、对于网络流图G,流量最大的可行流f,称为最大流。

7、弧的类型:

  1. a.饱和弧:即f(u,v)=c(u,v);
  2. b.非饱和弧:即f(u,v) < c(u,v);
  3. c.零流弧:即f(u,v)=0;
  4. d.非零流弧:即f(u,v)>0.

8、链:

  在容量网络中,称顶点序列(u1,u2,u3,u4,..,un,v)为一条链要求相邻的两个顶点之间有一条弧.

  设P是G中一条从Vs到Vt的链,约定从Vs指向Vt的方向为正方向.在链中并不要求所有的弧的方向都与链的方向相同.

性质

1、对于任意一个时刻,设f(u,v)实际流量,则整个图G的流网络满足3个性质:

  1. 容量限制:对任意u,v∈V,f(u,v)≤c(u,v)。
  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点本身不会"制造"和"消耗"流量。

2、最大流最小割定理:一个图的最大流等于其最小割。(割掉每条可行流上的最小流量边)。

Dinic算法:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<cstdlib>

const int inf=0x7fffffff;

using namespace std;

int n,m,S,T;
int a,b,c;
int head[10008],vis[10008],dis[10008],num_edge=1;
int deep[10008];

struct Edge{
    int next,to,dis;
}edge[100008<<1];

queue <int> q;

void addedge(int from,int to,int dis)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    edge[num_edge].dis=dis;
    head[from]=num_edge;
}

bool bfs()
{
    memset(deep,0,sizeof(deep));
    while(!q.empty()) q.pop();
    deep[S]=1;
    q.push(S);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(deep[v]==0&&edge[i].dis)
            {
                deep[v]=deep[u]+1;
                q.push(v);
            }
        }
    }
    if(deep[T]==0) return 0;
    else return 1;
}

int dfs(int u,int dist)
{
    if(u==T) return dist;
    for(int i=head[u];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(deep[v]==deep[u]+1&&edge[i].dis!=0)
        {
            int di=dfs(v,min(dist,edge[i].dis));
            if(di>0)
            {
                edge[i].dis-=di;
                edge[i^1].dis+=di;
                return di;
            }
        }
    }
    return 0;
}

int Dinic()
{
    int ans=0;
    while(bfs())
    {
        while(int di=dfs(S,inf))
        {
            ans+=di;
        }
    }
    return ans;
}

int main()
{
    scanf("%d %d %d %d",&n,&m,&S,&T);
    for(int i=1;i<=m;++i)
    {
        scanf("%d %d %d",&a,&b,&c);
        addedge(a,b,c);
        addedge(b,a,c);
    }
    printf("%d",Dinic());
    return 0;
}

 

posted @ 2019-06-11 18:48  _hhs  阅读(213)  评论(0编辑  收藏  举报