最大流之多源汇点,关键边

一.多源汇点

题目:

多个源点,不就是这几个源点的流量是不守恒的吗,我们直接建立超级源点和汇点,跑dinic即可。因为多个源汇点的流始终是单向的,我们只需要提供一个起始点和承接点即可

代码如下:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

const int N=1e4+10,M=(2*N+1e5+10)*2,INF=1e9;
int S,T;
int h[N],ne[M],e[M],f[M],idx;
int d[N],cur[N];
void add(int a, int b, int c){
    e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
    e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}

bool bfs(){
    memset(d,-1,sizeof d);
    queue<int>q;
    q.push(S);
    cur[S]=h[S];d[S]=0;
    while(!q.empty()){
        int t=q.front();
        q.pop();
        for(int i=h[t]; ~i; i=ne[i]){
            int ver=e[i];
            if(d[ver]==-1 && f[i]){
                cur[ver]=h[ver];
                d[ver]=d[t]+1;
                if(ver==T)return true;
                q.push(ver);
            }
        }
    }
    return false;
}

int find(int u, int limit){
    if(u==T)return limit;
    int flow=0;
    for(int i=cur[u]; ~i && flow<limit; i=ne[i]){
        int ver=e[i];
        cur[u]=i;
        if(d[ver]==d[u]+1 && f[i]){
            int t=find(ver,min(f[i],limit-flow));
            if(!t)d[ver]=-1;
            f[i]-=t;f[i^1]+=t;flow+=t;
        }
    }
    return flow;
    
}
int dinic(){
    int res=0,flow=0;
    while(bfs())while(flow=find(S,INF))res+=flow;
    return res;
}
int main(){
    memset(h,-1,sizeof h);
    int n,m,s,t;
    cin>>n>>m>>s>>t;
    S=0,T=n+1;
    for(int i=0; i<s; i++){
        int tt;
        cin>>tt;
        add(S,tt,INF);
    }
    for(int i=0; i<t; i++){
        int tt;
        cin>>tt;
        add(tt,T,INF);
    }
    for(int i=0; i<m; i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    cout<<dinic()<<endl;
}

二.关键边

题目:

无非就是增加一条边,然后是否有增广路的情况;

下面给出一个O(n^2*m)的做法,对于一条边,我们扩大容量,是否有增广路。首先我们先跑一遍dinic求残余网络。然后对于每一条容量为0的边u->v(>0的边一定没有增广路了),查看从源点S是否能到u,和从v是否能到T;如果条件满足,那就存在增广路;

代码实现如下:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;

const int N=1e4+10,M=(2*N+1e5+10)*2,INF=1e9;
int S,T;
int h[N],ne[M],e[M],f[M],idx;
int d[N],cur[N];
bool vis_s[N],vis_t[N];
void add(int a, int b, int c){
    e[idx]=b,f[idx]=c,ne[idx]=h[a],h[a]=idx++;
    e[idx]=a,f[idx]=0,ne[idx]=h[b],h[b]=idx++;
}

bool bfs(){
    memset(d,-1,sizeof d);
    queue<int>q;
    q.push(S);
    cur[S]=h[S];d[S]=0;
    while(!q.empty()){
        int t=q.front();
        q.pop();
        for(int i=h[t]; ~i; i=ne[i]){
            int ver=e[i];
            if(d[ver]==-1 && f[i]){
                cur[ver]=h[ver];
                d[ver]=d[t]+1;
                if(ver==T)return true;
                q.push(ver);
            }
        }
    }
    return false;
}

int find(int u, int limit){
    if(u==T)return limit;
    int flow=0;
    for(int i=cur[u]; ~i && flow<limit; i=ne[i]){
        int ver=e[i];
        cur[u]=i;
        if(d[ver]==d[u]+1 && f[i]){
            int t=find(ver,min(f[i],limit-flow));
            if(!t)d[ver]=-1;
            f[i]-=t;f[i^1]+=t;flow+=t;
        }
    }
    return flow;

}
int dinic(){
    int res=0,flow=0;
    while(bfs())while(flow=find(S,INF))res+=flow;
    return res;
}

void dfs(int u, bool st[], int fla){
    st[u]=true;
    for(int i=h[u]; ~i; i=ne[i]){
        int ver=e[i];
        int j=i^fla;
        if(f[j] && !st[ver]){
            dfs(ver,st,fla);
        }
    }
}
int main(){
    memset(h,-1,sizeof h);
    int n,m;
    cin>>n>>m;
    S=0,T=n-1;
    
    for(int i=0; i<m; i++){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
    }
    dinic();
    dfs(S,vis_s,0);
    dfs(T,vis_t,1);
    int res=0;
    for(int i=0; i<2*m; i+=2){
        if(!f[i] && vis_t[e[i]] && vis_s[e[i^1]]){
            res++;
        }
    }
    cout<<res<<endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值