zoukankan      html  css  js  c++  java
  • 网络流之最大流 模板 (洛谷3376)

    题目描述

    如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。

    输入输出格式

    输入格式:
    第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

    接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)

    输出格式:
    一行,包含一个正整数,即为该网络的最大流。

    输入输出样例

    输入样例#1: 复制
    4 5 4 3
    4 2 30
    4 3 20
    2 3 20
    2 1 30
    1 3 40
    输出样例#1: 复制
    50
    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,M<=25

    对于70%的数据:N<=200,M<=1000

    对于100%的数据:N<=10000,M<=100000

    样例说明:
    这里写图片描述

    题目中存在3条路径:

    4–>2–>3,该路线可通过20的流量

    4–>3,可通过20的流量

    4–>2–>1–>3,可通过10的流量(边4–>2之前已经耗费了20的流量)

    故流量总计20+20+10=50。输出50。

    最大流,第一种是Edmonds-Karp 增广路算法。
    思想为不断用bfs找增广路。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    const int MAXN = 10005;
    const int MAXM = 100005;
    const int inf = 0x3f3f3f3f;
    
    struct Edge{
        int nxt,to,v;
    }edge[MAXM*2];
    
    int n,m,cnt=1,ans,S,T;   //cnt从1开始,因为要取^。
    int head[MAXN],incf[MAXN],pre[MAXN];   //pre记录前驱。
    bool vis[MAXN];
    queue<int> q;
    
    inline void add(int bg,int ed,int val){
        edge[++cnt].to=ed;
        edge[cnt].nxt=head[bg];
        edge[cnt].v=val;
        head[bg]=cnt;
    } 
    
    inline bool bfs(){
        memset(vis,false,sizeof(vis));
        while(q.size()) q.pop();         //清空队列。
        q.push(S);vis[S]=1;
        incf[S]=inf;                   //最大流。
        while(q.size()){
            int x=q.front();q.pop();
            for(register int i=head[x];i;i=edge[i].nxt){
                int v=edge[i].to;
                if(edge[i].v && !vis[v]){
                    incf[v]=min(incf[x],edge[i].v);
                    pre[v]=i;
                    q.push(v);
                    vis[v]=1;
                    if(v==T) return 1;
                }
            }
        }
        return 0;
    }
    
    inline void update(){
        int x=T;
        while(x!=S){
            int i=pre[x];
            edge[i].v-=incf[T];
            edge[i^1].v+=incf[T];
            x=edge[i^1].to;
        }
        ans+=incf[T];
    }
    
    int main(){
        scanf("%d%d%d%d",&n,&m,&S,&T);
        for(register int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,0);
        }
        while(bfs()) update();
        printf("%d",ans);
        return 0;
    }

    第二种为dinic算法。
    是Edmonds-Kerp的优化,采用分层的思想。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    
    using namespace std;
    const int MAXN = 10005;
    const int MAXM = 100005;
    const int inf = 0x3f3f3f3f;
    
    struct Edge{
        int nxt,to,v;
    }edge[MAXM*2]; 
    
    int n,m,head[MAXN],cnt=1;
    int S,T,ans,d[MAXN];   //记录层数
    queue<int> q;
    
    inline void add(int bg,int ed,int val){
        edge[++cnt].to=ed;
        edge[cnt].nxt=head[bg];
        edge[cnt].v=val;
        head[bg]=cnt;
    }
    
    inline bool bfs(){
        memset(d,0,sizeof(d));
        while(q.size()) q.pop();
        q.push(S);d[S]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=head[x];i;i=edge[i].nxt){
                int v=edge[i].to;
                if(edge[i].v && !d[v]){
                    d[v]=d[x]+1;
                    q.push(v);
                    if(v==T) return 1;
                }
            }
        }
        return 0;
    } 
    
    inline int dinic(int x,int flow){
        if(x==T) return flow;
        int res=flow,k;
        for(int i=head[x];i && res;i=edge[i].nxt){
            int v=edge[i].to;
            if(edge[i].v && d[v]==d[x]+1){
                k=dinic(v,min(res,edge[i].v));
                if(!k) d[v]=0;
                edge[i].v-=k;
                edge[i^1].v+=k;
                res-=k;
            }
        }
        return flow-res;
    }
    
    int main(){
        scanf("%d%d%d%d",&n,&m,&S,&T);
        for(register int i=1;i<=m;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,0);
        }
        int flow=0;
        while(bfs()) {flow=dinic(S,inf);ans+=flow;}
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    P4047 部落划分
    P1440 求m区间的最小值
    P2880 平衡的阵容
    P2700 逐个击破
    P2814 家谱 map模版
    P4403 秦腾与教学评估
    无油无糖低脂酸奶芒果蛋糕
    紫薯铜锣烧
    Spring In Action ③
    Spring In Action ②
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9677120.html
Copyright © 2011-2022 走看看