网络流模板汇总

很棒的最小割模型论文(手动置顶)

论文链接

Dinic

interger型
#include "bits/stdc++.h"
#define hhh cerr<<"hhh"<<endl
#define see(x) cerr<<(#x)<<'='<<(x)<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}

const int maxn = 1e5+7;
const int maxm = 3e5+7;
const int inf = 0x3f3f3f3f;

int head[maxn], to[maxm], w[maxm], nxt[maxm], tot=1;
int cur[maxn], level[maxn];

void add_edge(int u, int v, int c) {
    ++tot; to[tot]=v; w[tot]=c; nxt[tot]=head[u]; head[u]=tot;
    ++tot; to[tot]=u; w[tot]=0; nxt[tot]=head[v]; head[v]=tot;
}

bool bfs(int s, int t) {
    memset(level,0,sizeof(level));
    queue<int> q;
    level[s]=1;
    q.push(s);
    while(!q.empty()) {
        int u=q.front(); q.pop();
        for(int i=head[u]; i; i=nxt[i]) {
            int v=to[i];
            if(!w[i]||level[v]) continue;
            level[v]=level[u]+1;
            q.push(v);
        }
    }
    return level[t];
}

int dfs(int u, int t, int flow) {
    if(u==t||flow==0) return flow;
    int f, ret=0;
    for(int &i=cur[u]; i; i=nxt[i]) {
        int v=to[i];
        if(level[v]==level[u]+1&&(f=dfs(v,t,min(flow,w[i])))>0) {
            w[i]-=f; w[i^1]+=f;
            flow-=f; ret+=f;
            if(!flow)break;
        }
    }
    if(!ret) level[u]=0;
    return ret;
}

int dinic(int s, int t) {
    int ret=0;
    while(bfs(s,t)) memcpy(cur,head,sizeof(cur)), ret+=dfs(s,t,inf);
    return ret;
}

int main() {
    int n=read(), m=read(), s=read(), t=read();
    for(int i=1; i<=m; ++i) {
        int u=read(), v=read(), w=read();
        add_edge(u,v,w);
    }
    printf("%d\n", dinic(s,t));
}
double型
#include "bits/stdc++.h"
#define hhh cerr<<"hhh"<<endl
#define see(x) cerr<<(#x)<<'='<<(x)<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}

const int maxn = 1e5+7;
const int maxm = 3e5+7;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

int head[maxn], to[maxm], nxt[maxm], tot=1;
double w[maxm];
int cur[maxn], level[maxn];

void add_edge(int u, int v, double c) {
    ++tot; to[tot]=v; w[tot]=c; nxt[tot]=head[u]; head[u]=tot;
    ++tot; to[tot]=u; w[tot]=0; nxt[tot]=head[v]; head[v]=tot;
}

bool bfs(int s, int t) {
    memset(level,0,sizeof(level));
    queue<int> q;
    level[s]=1;
    q.push(s);
    while(!q.empty()) {
        int u=q.front(); q.pop();
        for(int i=head[u]; i; i=nxt[i]) {
            int v=to[i];
            if(fabs(w[i])<=eps||level[v]) continue;
            level[v]=level[u]+1;
            q.push(v);
        }
    }
    return level[t];
}

double dfs(int u, int t, double flow) {
    if(u==t||fabs(flow)==0) return flow;
    double f, ret=0;
    for(int &i=cur[u]; i; i=nxt[i]) {
        int v=to[i];
        if(level[v]==level[u]+1&&(f=dfs(v,t,min(flow,w[i])))>=eps) {
            w[i]-=f; w[i^1]+=f;
            flow-=f; ret+=f;
            if(fabs(flow)<=eps)break;
        }
    }
    if(fabs(ret)<=eps) level[u]=0;
    return ret;
}

double dinic(int s, int t) {
    double ret=0;
    while(bfs(s,t)) memcpy(cur,head,sizeof(cur)), ret+=dfs(s,t,5e18);
    return ret;
}

int main() {
    int n=read(), m=read(), s=read(), t=read();
    for(int i=1; i<=m; ++i) {
        int u=read(), v=read();
        double w; scanf("%lf", &w);
        add_edge(u,v,w);
    }
    printf("%.3f\n", dinic(s,t));
}

费用流

#include "bits/stdc++.h"
#define hhh cerr<<"hhh"<<endl
#define see(x) cerr<<(#x)<<'='<<(x)<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
inline int read() {int x=0,f=1;char c=getchar();while(c!='-'&&(c<'0'||c>'9'))c=getchar();if(c=='-')f=-1,c=getchar();while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();return f*x;}

const int maxn = 2e4+7;
const int maxm = 2e5+7;
const int inf = 0x3f3f3f3f;

ll maxflow, mincost;
int last[maxn], pre[maxn], dis[maxn], now[maxn];
int head[maxn], to[maxm], flow[maxm], cost[maxm], nxt[maxm], tot=1;
bool inq[maxn];

void add_edge(int u,int v,int f,int c) {
    ++tot; to[tot]=v; flow[tot]=f; cost[tot]=c; nxt[tot]=head[u]; head[u]=tot;
    ++tot; to[tot]=u; flow[tot]=0; cost[tot]=-c; nxt[tot]=head[v]; head[v]=tot;
}

void init() { tot=1; memset(head,0,sizeof(head)); mincost=maxflow=0; }

bool spfa(int s, int t) {
    memset(dis,inf,sizeof(dis));
    memset(now,inf,sizeof(now));
    memset(inq,0,sizeof(inq));
    queue<int> q;
    dis[s]=0; pre[t]=-1; q.push(s); inq[s]=1;
    while(!q.empty()) {
        int u=q.front(); q.pop(); inq[u]=0;
        for(int i=head[u]; i; i=nxt[i]) {
            int v=to[i];
            if(flow[i]>0&&dis[v]>dis[u]+cost[i]) {
                dis[v]=dis[u]+cost[i];
                now[v]=min(now[u],flow[i]);
                last[v]=i; pre[v]=u;
                if(!inq[v]) q.push(v), inq[v]=1;
            }
        }
    }
    return pre[t]!=-1;
}

void MCMF(int s, int t) {
    while(spfa(s,t)) {
        int u=t;
        maxflow+=now[t];
        mincost+=now[t]*ll(dis[t]);
        while(u!=s) {
            flow[last[u]]-=now[t];
            flow[last[u]^1]+=now[t];
            u=pre[u];
        }
    }
}

int main() {
    int n=read(), m=read(), s=read(), t=read();
    for(int i=1; i<=m; ++i) {
        int u=read(), v=read(), w=read(), f=read();
        add_edge(u,v,w,f);
    }
    MCMF(s,t);
    printf("%lld %lld\n", maxflow, mincost);
}

最大权闭合子图

闭合图(针对有向图):图中点集的出边也在点集中。(相当于有向边终点是有向边起点的必要条件)

最大权闭合子图:图中每个点有点权,则权值最大的闭合子图为最大权闭合子图。

原闭合图构造:额外加入源点 s s s ,汇点 t t t ,与 s s s 相连的点( S S S )的点权都为正,与 t t t 相连的点( T T T )的点权都为负(0就随意啦),这两者的边权用点权(取绝对值)代替; S S S T T T 的连边边权为无穷。

最大权闭合子图权值为: ∑ S − W \displaystyle \sum{S}-W SW W W W为闭合图的最小割 )

(由于 < S , T > <S,T> <S,T> 都是无穷边,因此最小割一定是简单割,即所有割边都与源点或汇点相连)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值