网络流板子

dinic是loj上偷学长的(

注意几点:

id初值赋1才能让正向弧反向弧对应起来

很多题要拆点,一定保证空间

dfs里当前弧优化不能放在for循环里


Talk is cheap. Show you the code.
#include<cstdio>
#include<iostream>
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(int x=0,char ch=getchar()){
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    return x;
}

const int N=1e2+7,M=1e4+7;
const ll inf=1e18;

int n,m,S,T;
ll ans,c[M];
int head[N],to[M],nx[M],id=1;
inline void add(int a,int b,int cc){
    nx[++id]=head[a]; head[a]=id; to[id]=b; c[id]=cc; 
}
inline void Add(int a,int b,int c){
    add(a,b,c); add(b,a,0);
}

int q[N],hd,tl;
int dis[N],Hd[N];

inline bool bfs(){
    memset(dis,0x3f,sizeof(dis));
    memcpy(head,Hd,sizeof(head));
    q[hd=tl=1]=S; dis[S]=0;
    while(hd<=tl){
        int x=q[hd++];
        for(int i=head[x];i;i=nx[i]) if(c[i]){
            int t=to[i];
            if(dis[t]>dis[x]+1){
                dis[t]=dis[x]+1;
                q[++tl]=t;
            }
        }
        if(x==T) return 1;
    }
    return 0;
}

ll dfs(int x,ll in){
    if(x==T) return in;
    ll rest=in,go;
    for(int i=head[x];i;head[x]=i=nx[i]) if(c[i]){
        int t=to[i];
        if(dis[t]==dis[x]+1){
            go=dfs(t,min(rest,c[i]));
            if(go) c[i]-=go,c[i^1]+=go,rest-=go;
            else dis[t]=0;
        }
        if(!rest) break;
    }
    return in-rest;
}

int main(){
    n=read(); m=read();
    S=read(); T=read();
    while(m--){
        int u=read(),v=read();
        Add(u,v,read());
    }
    memcpy(Hd,head,sizeof(Hd));
    while(bfs()) ans+=dfs(S,inf);
    printf("%lld\n",ans);
    return 0;
}

用自己码风写了一遍(其实差不多
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL;
    typedef double DB;
    int read(){
        int x=0,f=0; char ch=getchar();
        while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
        while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return f?-x:x;
    } char output[50];
    void write(LL x,char sp){
        int len=0;
        if(x<0) x=-x, putchar('-');
        do{ output[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
    }
    void ckmin(int &x,int y){ x=x<y?x:y; }
    void ckmax(int &x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=210,MM=100010;
int n,m;
LL ans;

namespace Network_Flows{
    int s,t,ql,qr,q[NN],idx=1;
    int to[MM],nex[MM],hd[NN],dis[NN],head[NN];
    LL c[MM];
    void add(int a,int b,int d){ to[++idx]=b; nex[idx]=head[a]; head[a]=idx; c[idx]=d; }
    void link(int a,int b,int c){ add(a,b,c); add(b,a,0); }
    bool bfs(){
        memset(dis,0x3f,sizeof(dis));
        memcpy(head,hd,sizeof(hd));
        q[ql=qr=1]=s; dis[s]=0;
        while(ql<=qr){
            int u=q[ql++];
            for(int v,i=head[u];i;i=nex[i]) if(c[i])
                if(dis[v=to[i]]>dis[u]+1){
                    dis[v]=dis[u]+1;
                    q[++qr]=v;
                }
            if(u==t) return 1;
        }
        return 0;
    }
    LL dfs(int u,LL in){
        if(u==t) return in;
        LL rest=in,go;
        for(int v,i=head[u];i;head[u]=i=nex[i]) if(c[i]){
            if(dis[v=to[i]]==dis[u]+1){
                go=dfs(v,min(c[i],rest));
                if(go) c[i]-=go, c[i^1]+=go, rest-=go;
                else dis[v]=0;
            }
            if(!rest) break;
        }
        return in-rest;
    }
    void dinic(){
        memcpy(hd,head,sizeof(head));
        while(bfs()) ans+=dfs(s,LLONG_MAX);
    }
} using namespace Network_Flows;

signed main(){
    n=read(); m=read(); s=read(); t=read();
    for(int u,v,i=1;i<=m;i++)
        u=read(), v=read(), link(u,v,read());
    dinic();
    write(ans,'\n');
    return 0;
}
EK最小费用最大流
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL;
    typedef double DB;
    int read(){
        int x=0,f=0; char ch=getchar();
        while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
        while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return f?-x:x;
    } char output[50];
    void write(LL x,char sp){
        int len=0;
        if(x<0) x=-x, putchar('-');
        do{ output[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
    }
    void ckmin(int &x,int y){ x=x<y?x:y; }
    void ckmax(int &x,int y){ x=x>y?x:y; }
} using namespace IO;

const int NN=50010,MM=500010;
int n,m;

namespace Network_Flows{
    int S,T,ql,qr,flow,cost,q[NN],idx=1;
    int c[MM],w[MM],to[MM],nex[MM],dis[NN],inc[NN],pre[NN],head[NN];
    bool vis[NN];
    void add(int a,int b,int x,int y){
        to[++idx]=b; nex[idx]=head[a]; head[a]=idx; c[idx]=x; w[idx]=y;
        to[++idx]=a; nex[idx]=head[b]; head[b]=idx; c[idx]=0; w[idx]=-y;
    }
    bool spfa(){
        memset(dis,0x3f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        dis[S]=0; inc[S]=INT_MAX;
        vis[q[ql=qr=1]=S]=1;
        while(ql<=qr){
            int u=q[ql++]; vis[u]=0;
            for(int v,i=head[u];i;i=nex[i]) if(c[i])
                if(dis[v=to[i]]>dis[u]+w[i]){
                    dis[v]=dis[u]+w[i];
                    inc[v]=min(inc[u],c[i]);
                    pre[v]=i;
                    if(!vis[v]) vis[q[++qr]=v]=1;
                }
        }
        return dis[T]<1e9;
    }
    void MCMF(){
        while(spfa()){
            flow+=inc[T]; cost+=inc[T]*dis[T];
            int u=T,i;
            while(u!=S){
                i=pre[u];
                c[i]-=inc[T];
                c[i^1]+=inc[T];
                u=to[i^1];
            }
        }
    }
} using namespace Network_Flows;

signed main(){
    n=read(); m=read(); S=read(); T=read();
    for(int a,b,x,y,i=1;i<=m;i++)
        a=read(),b=read(),x=read(),y=read(),add(a,b,x,y);
    MCMF();
    write(flow,' '); write(cost,'\n');
    return 0;
}

带上下界的就不放了--可以看达哥的博

先保证下界,然后连出超级源汇(如果是有源汇还要汇点向源点连边),之后该跑啥跑啥就好。

最小可行流先不连汇源跑一遍,再连上跑一遍,看汇源之间边的流量即可。

for(int i=1;i<=t;i++)
    if(dis[i]>0) add(S,i,dis[i]);
    else if(dis[i]<0) add(i,T,-dis[i]);
dinic();
link(t,s,0,INT_MAX);
dinic();
write(c[idx],'\n');
posted @ 2021-07-30 21:42  keen_z  阅读(61)  评论(0编辑  收藏  举报