EK&&Dinic

EK

//EK
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3+1,M = 2e4+1,INF = 1e9+7;
int n,m,S,T;
struct op{
    int nxt,f/*容量*/,to;
}e[M];
int head[N],NUM;
int d[N]/*当前点所有边容量的最小值*/,pre[N]/*前驱*/;
bool vis[N]/*判重*/;
void add(int frm,int to,int dis) {
    e[NUM] = op{head[frm],dis,to}; head[frm] = NUM++;
    e[NUM] = op{head[to],0,frm}; head[to] = NUM++;
}//边从0开始编号,方便边^1来表示下一条边,head数组初始化为-1
bool bfs() {//找增广路
    queue<int>q;
    memset(vis,0,sizeof vis);
    q.push(S); vis[S] = 1; d[S] = INF;
    while(!q.empty()) {
        int x = q.front();q.pop();
        for(int i = head[x];~i;i = e[i].nxt) {
            int v = e[i].to;
            if(!vis[v]&&e[i].f) {//可以更新
                vis[v] = 1;
                d[v] = min(d[x],e[i].f);//更新最小值
                pre[v] = i;//这个点的前驱边
                if(v == T) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
int EK() {
    int res = 0;
    while(bfs()) {//1.更新增广路
        res += d[T];
        for(int i = T;i != S;i = e[pre[i]^1].to) {
            e[pre[i]].f -= d[T];//当前边容量减少
            e[pre[i]^1].f += d[T];//反向边容量增加
        }//2.更新残留网络
    }
    return res;
}
int main() {
    cin>>n>>m>>S>>T;
    memset(head,-1,sizeof head);
    while(m--) {
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
    }
    cout<<EK();
    return 0;
}

Dinic

//Dinic
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+1,M = 2e5+1,INF = 1e9+7;
int n,m,S,T;
struct op{
    int to,nxt,f;
}e[M];
int head[M],NUM;
int d[M]/*层数*/,cur[M]/*当前弧优化*/;
//在邻接表枚举当前点的所有边的时候,会按顺序分配,即某些边会满
//那么下一次搜到这个点的时候就可直接跳过
void add(int frm,int to,int w) {
    e[NUM] = op{to,head[frm],w}; head[frm] = NUM++;
    e[NUM] = op{frm,head[to],0}; head[to] = NUM++;
}
//其余同EK
bool bfs() {//找增广路同时建立分层图
    queue<int>q;
    memset(d,-1,sizeof d);
    q.push(S); d[S] = 0; cur[S] = head[S]/*从第一条边开始走*/;
    while(!q.empty()) {
        int x = q.front(); q.pop();
        for(int i = head[x];~i;i = e[i].nxt) {
            int v = e[i].to;
            if(d[v] == -1&&e[i].f) {
                d[v] = d[x] + 1;//当前层数 = 上一层数 + 1
                cur[v] = head[v];//这个点的当前弧是第一条边
                if(v == T) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}
int find(int u,int limit) {//从S流向u最大的流量为limit
    if(u == T) return limit;
    int flow = 0;//从u往后流的最大流量为flow
    for(int i = cur[u]/*从当前没有满的路径开始*/;~i&&flow<limit;i = e[i].nxt) {
        cur[u] = i;//i之前的边都满了
        int v = e[i].to;
        if(d[v] == d[u] + 1&&e[i].f) {//当前点是在上一个点的下一层
            int x = find(v,min(e[i].f,limit-flow));
            if(!x) d[v] = -1;//如果当点不可用(没有路径)就删掉
            e[i].f -= x; e[i^1].f += x;//当前边减去流量,反向边加上流量
            flow += x;//最大流量加上这些流量
        }
    }
    return flow;
}
int dinic() {
    int res = 0,flow;
    while(bfs())//只要它有增广路径
        while(flow = find(S,INF))//就全部找出来
            res += flow;//把总共能加的流量加起来
    //下次迭代继续找剩余的增广路
    return res;
}
int main() {
    memset(head,-1,sizeof head);
    cin>>n>>m>>S>>T;
    while(m--) {
        int u,v,w;
        cin>>u>>v>>w;
        add(u,v,w);
    }
    cout<<dinic();
}
posted @ 2022-06-10 18:02  双枫  阅读(25)  评论(0编辑  收藏  举报