上下界网络流

代码均使用自这里,特此注明出处。

无源汇上下界可行流

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+1212;
const int N=250;
const int inf=0x3f3f3f3f;
int ed[N],st[N],s,t,cnt,head[N],n,m,tflow,d[N],l[maxn],cur[N];
struct node {
    int next,to,cap,flow;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow) {
    e[cnt].next=head[from];
    e[cnt].cap=cap;
    e[cnt].flow=flow;
    e[cnt].to=to;
    head[from]=cnt++;
}
bool BFS(int s,int t) {//分层
    memset(d,0,sizeof(d));
    for(int i=0; i<=n+1; i++)//复制每个点的head
        cur[i]=head[i];
    queue<int>q;
    q.push(s);
    d[s]=1;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=head[u]; ~i; i=e[i].next) {
            int v=e[i].to;
            if(!d[v]&&e[i].cap>e[i].flow) {//如果可以增流
                d[v]=d[u]+1;
                q.push(v);
                if(v==t)return 1;
            }
        }
    }
    return 0;
}
int DFS(int u,int flow,int t) {
    if(u==t)return flow;
    int res=flow;//res存储当前节点的可增流值
    for(int i=cur[u]; ~i&&res; i=e[i].next) {//遍历满足条件的邻边并增流
        cur[u]=i;//当前弧优化
        int v=e[i].to;
        if(d[v]==d[u]+1&&e[i].cap>e[i].flow) {
            int k=DFS(v,min(res,e[i].cap-e[i].flow),t);//获得最小的回溯流
            if(!k) {
                d[v]=0;
                continue;
            }
            e[i].flow+=k;//获得最小的回溯流后增流
            e[i^1].flow-=k;
            res-=k;//可增流值减少,因为已经有邻边增流
        }
    }
    return flow-res;//返回实际的总增流值
}
int Dinic(int s,int t) {
    int ans=0;//存储最大流
    while(BFS(s,t))for(int i=1;i<=n;i++)ans+=DFS(s,inf,t);
    return ans;
}
signed main() {
    //freopen("test.txt","r",stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>n>>m;
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++) {
        int u,v,low,up;
        cin >>u>>v>>low>>up;
        Add(u,v,up-low,0);
        Add(v,u,0,0);
        st[u]+=low;
        ed[v]+=low;
        tflow+=low;
        l[i]=low;//记录边的,不要求输出答案可以不要
    }
    s=0,t=n+1;
    for(int i=1; i<=n; i++) {
        Add(s,i,ed[i],0);
        Add(i,s,0,0);
        Add(i,t,st[i],0);
        Add(t,i,0,0);
    }
    if(Dinic(s,t)^tflow) cout <<"NO";
    else {
        cout <<"YES\n";
        for(int i=1; i<=m; i++)
            cout <<e[2*(i-1)].flow+l[i]<<endl;
    }
    return 0;
}

有源汇上下界最大流

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+1212;
const int N=250;
const int inf=0x3f3f3f3f;
int ed[N],st[N],s,t,sx,tx,cnt,head[N],n,m,tflow,d[N],cur[N];
struct node {
    int next,to,cap,flow;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow) {
    e[cnt].next=head[from];
    e[cnt].cap=cap;
    e[cnt].flow=flow;
    e[cnt].to=to;
    head[from]=cnt++;
}
bool BFS(int s,int t) {//分层
    memset(d,0,sizeof(d));
    for(int i=0; i<=n+1; i++)//复制每个点的head
        cur[i]=head[i];
    queue<int>q;
    q.push(s);
    d[s]=1;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=head[u]; ~i; i=e[i].next) {
            int v=e[i].to;
            if(!d[v]&&e[i].cap>e[i].flow) {//如果可以增流
                d[v]=d[u]+1;
                q.push(v);
                if(v==t)return 1;
            }
        }
    }
    return 0;
}
int DFS(int u,int flow,int t) {
    if(u==t)return flow;
    int res=flow;//res存储当前节点的可增流值
    for(int i=cur[u]; ~i&&res; i=e[i].next) {//遍历满足条件的邻边并增流
        cur[u]=i;//当前弧优化
        int v=e[i].to;
        if(d[v]==d[u]+1&&e[i].cap>e[i].flow) {
            int k=DFS(v,min(res,e[i].cap-e[i].flow),t);//获得最小的回溯流
            if(!k) {
                d[v]=0;
                continue;
            }
            e[i].flow+=k;//获得最小的回溯流后增流
            e[i^1].flow-=k;
            res-=k;//可增流值减少,因为已经有邻边增流
        }
    }
    return flow-res;//返回实际的总增流值
}
int Dinic(int s,int t) {
    int ans=0;//存储最大流
    while(BFS(s,t))for(int i=1; i<=n; i++)ans+=DFS(s,inf,t);
    return ans;
}
signed main() {
    //freopen("test.txt","r",stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>n>>m>>s>>t;
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++) {
        int u,v,low,up;
        cin >>u>>v>>low>>up;
        Add(u,v,up-low,0);
        Add(v,u,0,0);
        st[u]+=low;
        ed[v]+=low;
        tflow+=low;
        //l[i]=low;
    }
    sx=0,tx=n+1;
    for(int i=1; i<=n; i++) {
        Add(sx,i,ed[i],0);
        Add(i,sx,0,0);
        Add(i,tx,st[i],0);
        Add(tx,i,0,0);
    }
    Add(t,s,inf,0);
    Add(s,t,0,0);
    if(Dinic(sx,tx)^tflow) cout <<"please go home to sleep";
    else 
        cout <<Dinic(s,t)<<endl;
    return 0;
}

有源汇上下界最小流

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+30000;
const int N=7e4+5;
const int inf=1e10;
int ed[N],st[N],s,t,sx,tx,cnt,head[N],n,m,tflow,d[N],cur[N];
struct node {
    int next,to,cap,flow;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow) {
    e[cnt].next=head[from];
    e[cnt].cap=cap;
    e[cnt].flow=flow;
    e[cnt].to=to;
    head[from]=cnt++;
}
bool BFS(int s,int t) {//分层
    memset(d,0,sizeof(d));
    for(int i=0; i<=n+1; i++)//复制每个点的head
        cur[i]=head[i];
    queue<int>q;
    q.push(s);
    d[s]=1;
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        for(int i=head[u]; ~i; i=e[i].next) {
            int v=e[i].to;
            if(!d[v]&&e[i].cap>e[i].flow) {//如果可以增流
                d[v]=d[u]+1;
                q.push(v);
                if(v==t)return 1;
            }
        }
    }
    return 0;
}
int DFS(int u,int flow,int t) {
    if(u==t)return flow;
    int res=flow;//res存储当前节点的可增流值
    for(int i=cur[u]; ~i&&res; i=e[i].next) {//遍历满足条件的邻边并增流
        cur[u]=i;//当前弧优化
        int v=e[i].to;
        if(d[v]==d[u]+1&&e[i].cap>e[i].flow) {
            int k=DFS(v,min(res,e[i].cap-e[i].flow),t);//获得最小的回溯流
            if(!k) {
                d[v]=0;
                continue;
            }
            e[i].flow+=k;//获得最小的回溯流后增流
            e[i^1].flow-=k;
            res-=k;//可增流值减少,因为已经有邻边增流
        }
    }
    return flow-res;//返回实际的总增流值
}
int Dinic(int s,int t) {
    int ans=0;//存储最大流
    while(BFS(s,t))ans+=DFS(s,inf,t);
    return ans;
}
signed main() {
    //freopen("4.in","r",stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>n>>m>>s>>t;
    memset(head,-1,sizeof(head));
    for(int i=1; i<=m; i++) {
        int u,v,low,up;
        cin >>u>>v>>low>>up;
        Add(u,v,up-low,0);
        Add(v,u,0,0);
        st[u]+=low;
        ed[v]+=low;
        tflow+=low;
    }
    sx=0,tx=n+1;
    for(int i=1; i<=n; i++) {
        Add(sx,i,ed[i],0);
        Add(i,sx,0,0);
        Add(i,tx,st[i],0);
        Add(tx,i,0,0);
    }
    tflow-=Dinic(sx,tx);
    Add(t,s,inf,0);
    Add(s,t,0,0);
    tflow-=Dinic(sx,tx);
    if(tflow) cout <<"please go home to sleep";
    else
        cout <<e[cnt-2].flow;
    return 0;
}

有源汇上下界最小费用可行流

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e4+5;
const int N=1212;
const int inf=0x3f3f3f3f;
int ed[N],st[N],s,t,sx,tx,cnt,head[N],n,m,tflow,dis[N],pre[N];
bool vis[N];
struct node {
    int next,to,cap,flow,pay;
} e[maxn<<1];
void Add(int from,int to,int cap,int flow,int pay) {
    e[cnt].to=to;
    e[cnt].cap=cap;
    e[cnt].flow=flow;
    e[cnt].pay=pay;
    e[cnt].next=head[from];
    head[from]=cnt++;
}
bool SPFA(int s,int t) {
    queue<int>q;
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    memset(dis,0x3f,sizeof(dis));
    dis[s]=0;
    vis[s]=1;
    q.push(s);
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u]; ~i; i=e[i].next) {
            int v=e[i].to;
            if(e[i].cap>e[i].flow&&dis[v]>dis[u]+e[i].pay) {
                dis[v]=dis[u]+e[i].pay;
                pre[v]=i;
                if(vis[v])continue;
                vis[v]=1;
                q.push(v);
            }
        }
    }
    return pre[t]!=-1;
}
int MCMF(int s,int t) {
    int mincost=0;
    while(SPFA(s,t)) {
        int d=inf,v=t;
        while(v!=s) {
            int i=pre[v];
            d=min(d,e[i].cap-e[i].flow);//可增加的流量
            v=e[i^1].to;//换点
        }
        v=t;
        while(v!=s) {
            int i=pre[v];
            e[i].flow+=d;
            e[i^1].flow-=d;//实流
            v=e[i^1].to;
        }
        mincost+=dis[t]*d;
    }
    return mincost;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin>>n;
    memset(head,-1,sizeof(head));
    s=0,t=n+1,sx=t+1,tx=t+2;
    Add(s,1,inf,0,0),Add(1,s,0,0,0);
    for(int u=1; u<=n; u++) {
        cin >>m;
        while(m--) {
            int v,p;
            cin >>v>>p;
            Add(u,v,inf,0,p);
            Add(v,u,0,0,-p);
            st[u]++,ed[v]++;//这里的下界都是1
            tflow+=p;//加上1*p
        }
    }
    Add(t,s,inf,0,0);
    Add(s,t,0,0,0);
    for(int i=1; i<=n; i++) {
        Add(sx,i,ed[i],0,0);
        Add(i,sx,0,0,0);
        Add(i,tx,st[i],0,0);
        Add(tx,i,0,0,0);
        Add(i,t,inf,0,0);//需要与汇点连接,不要想当然
        Add(t,i,0,0,0);
    }
    cout <<MCMF(sx,tx)+tflow;
    return 0;
}

posted @ 2023-11-20 22:21  永无岛  阅读(4)  评论(0编辑  收藏  举报