首页 > 其他 > 详细

网络流学习笔记

时间:2019-10-11 20:28:39      阅读:68      评论:0      收藏:0      [点我收藏+]

本博客会随着后续刷题不断更新。

网络流属于图论一部分,可以解决二分图匹配等问题。

网络流图的特点为,有且仅有一个入度为0的点,并且有且仅有一个出度为0的点,且任意两点之间仅存在一条单向边。通常采用Dinic法,每次bfs搜索路径,若查询到则不断增广路径。

时间复杂度:在普通图下,时间复杂度$O(V^{2}E)$,在二分图中时间复杂度$O(\sqrt{V}E)$。

贴上网络流模板,这边采用邻接表建图。

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int,int> pii;
#define rep(i,x,y) for(int i=x;i<y;i++)
#define rept(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define de(x) cout<< #x<<" = "<<x<<endl
#define dd(x) cout<< #x<<" = "<<x<<" "
#define mes(a,b) memset(a,b,sizeof a)
const ll inf=1e18;
const int N=500010,M=300010;//N点数,M边数 
int head[N],ver[M],edge[M],Next[M],d[N];
int n,m,s,t,tot,maxflow;
queue<int> q;
void add(int x,int y,int z)//x到y建长度z单向边
{
    ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;//邻接表建边 
    ver[++tot]=x;edge[tot]=0,Next[tot]=head[y],head[y]=tot;
}
bool bfs()//判断是否有增广路
{
    mes(d,0);
    while(!q.empty()) q.pop();
    q.push(s);
    d[s]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=Next[i])
            if(edge[i]&& !d[ver[i]])
            {
                q.push(ver[i]);
                d[ver[i]]=d[x]+1;
                if(ver[i]==t) return 1;
            }
    }
    return 0;
}
int dinic(int x,ll flow)
{
    if(x==t) return flow;
    int rest=flow,k;
    for(int i=head[x];i&&rest;i=Next[i])
    {
        if(edge[i]&&d[ver[i]]==d[x]+1)
        {
            k=dinic(ver[i],min(rest,edge[i]));
            if(!k) d[ver[i]]=0;
            edge[i]-=k;
            edge[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>m;//n为点数,m为边数
    cin>>s>>t;//s起点,t终点 
    tot=1;
    rep(i,0,m)
    {
        int x,y,c;
        cin>>x>>y>>c;
        add(x,y,c);
    }
    int flow=0;
    while(bfs())
        while(flow=dinic(s,inf)) maxflow+=flow;
    cout<<maxflow<<"\n";
    return 0;
}

 

经典例题:飞行员配对问题https://www.luogu.org/problem/P2756

只需要将外国飞行员和源点相连,英国飞行员和终点相连,然后外国飞行员和英国飞行员建一条边权为1的边即可。

贴上洛谷2756AC代码

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair <int,int> pii;
#define rep(i,x,y) for(int i=x;i<y;i++)
#define rept(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define de(x) cout<< #x<<" = "<<x<<endl
#define dd(x) cout<< #x<<" = "<<x<<" "
#define mes(a,b) memset(a,b,sizeof a)
const ll inf=1e18;
const int N=205,M=200000;
int head[N],ver[M],edge[M],Next[M],d[N];
int n,m,s,t,tot,maxflow;
queue<int> q;

void add(int x,int y,int z)
{
    ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
    ver[++tot]=x;edge[tot]=0,Next[tot]=head[y],head[y]=tot;
}

bool bfs()
{
    mes(d,0);
    while(!q.empty()) q.pop();
    q.push(s);
    d[s]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=Next[i])
            if( edge[i] && !d[ver[i]] )
            {
                q.push(ver[i]);
                d[ver[i]]=d[x]+1;
                if(ver[i]==t) return 1;
            }
    }
    return 0;
}

int dinic(int x,ll flow)
{
    if(x==t) return flow;
    int rest=flow,k;
    for(int i=head[x];i&&rest;i=Next[i])
    {
        if(edge[i]&&d[ver[i]]==d[x]+1)
        {
            k=dinic(ver[i],min(rest,edge[i]));
            if(!k) d[ver[i]]=0;
            edge[i]-=k;
            edge[i^1]+=k;
            rest-=k;
        }
    }
    return flow-rest;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    mes(head,0);
    cin>>n>>m;
    s=0,t=n+m+1;
    tot=1;
    int x,y;
    while(cin>>x>>y)
    {
        if(x==-1&&y==-1) break;
        add(x,y,1);
    }
    rept(i,1,n)
        add(s,i,1);
    rept(i,n+1,n+m)
        add(i,t,1);
    int flow=0;
    while(bfs())
        while(flow=dinic(s,inf)) maxflow+=flow;
    
    if(!maxflow)
    {
        cout<<"No Solution!\n";
        return 0;
    }
    cout<<maxflow<<"\n";
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=Next[j])
        {
            if( j%2==0&&!edge[j] )
            {
                cout<<i<<" "<<ver[j]<<"\n";
            }
        }
    }
    return 0;
}

 

网络流学习笔记

原文:https://www.cnblogs.com/FZUzyz/p/11656547.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!