zoukankan      html  css  js  c++  java
  • [网络流24题(4/24)] 运输问题(最小费用最大流)

    传送门

    题意:

    (m)个仓库和(n)个零售商,第(i)个仓库送到第(j)个零售商需要花费(v[i][j])元。现在需要让仓库的供给量以及零售商的收获量相同,问最小花费以及最大花费。

    分析:

    相当经典的最小费用最大流的模型。因为要保证供给以及收获相同,即代表着流量平衡,因此我们可以让超级源点(sp)跟对应的仓库连一条流量为(a_i),费用为(0)的边,同时让对应的零售商跟超级汇点(ep)连一条流量为(b_i),费用为(0)的边。而对于仓库与零售商,我们只需要将仓库和零售商之间连一条流量为无穷,费用为(v[i][j])的边。

    对于最小花费问题,我们只需要在上述的图中跑最小费用最大流即可。

    而对于最大花费的问题,我们只需要将上述的图中的仓库与零售商的改为连一条流量为无穷,费用为(-v[i][j])的边,最后在新图上跑一边最小费用最大流,而最后最小费用的相反数即是答案。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 505;
    const int maxm = 20005;
    int head[maxn],cnt=0;
    int dis[maxn],vis[maxn],sp,ep,maxflow,cost;
    const int INF=0x3f3f3f3f;
    struct Node{
        int to,next,val,cost;
    }q[maxm<<1];
    void init(){
        memset(head,-1,sizeof(head));
        cnt=2;
        maxflow=cost=0;
    }
    void addedge(int from,int to,int val,int cost){
        q[cnt].to=to;
        q[cnt].next=head[from];
        q[cnt].val=val;
        q[cnt].cost=cost;
        head[from]=cnt++;
    }
    void add_edge(int from,int to,int val,int cost){
        addedge(from,to,val,cost);
        addedge(to,from,0,-cost);
    }
    bool spfa(){
        memset(vis,0,sizeof(vis));
        memset(dis,0x3f,sizeof(dis));
        dis[sp]=0;
        vis[sp]=1;
        queue<int>que;
        que.push(sp);
        while(!que.empty()) {
            int x = que.front();
            que.pop();
            vis[x]=0;
            for(int i=head[x];i!=-1;i=q[i].next){
                int to=q[i].to;
                if(dis[to]>dis[x]+q[i].cost&&q[i].val){
                    dis[to]=dis[x]+q[i].cost;
                    if(!vis[to]){
                        que.push(to);
                        vis[to]=1;
                    }
                }
            }
        }
        return dis[ep]!=0x3f3f3f3f;
    }
    int dfs(int x,int flow){
        if(x==ep){
            vis[ep]=1;
            maxflow+=flow;
            return flow;
        }
        int used=0;
        vis[x]=1;
        for(int i=head[x];i!=-1;i=q[i].next){
            int to=q[i].to;
            if((vis[to]==0||to==ep)&&q[i].val!=0&&dis[to]==dis[x]+q[i].cost){
                int minflow=dfs(to,min(flow-used,q[i].val));
                if(minflow!=0){
                    cost+=q[i].cost*minflow;
                    q[i].val-=minflow;
                    q[i^1].val+=minflow;
                    used+=minflow;
                }
                if(used==flow) break;
            }
        }
        return used;
    }
    int mincostmaxflow(){
        while(spfa()){
            vis[ep]=1;
            while(vis[ep]){
                memset(vis,0,sizeof(vis));
                dfs(sp,INF);
            }
        }
        return maxflow;
    }
    int a[maxn],b[maxn],v[maxn][maxn];
    int main()
    {
        int n,m;
        init();
        scanf("%d%d",&n,&m);
        sp=n+m+1,ep=n+m+2;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            add_edge(sp,i,a[i],0);
        }
        for(int i=1;i<=m;i++){
            scanf("%d",&b[i]);
            add_edge(i+n,ep,b[i],0);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&v[i][j]);
                add_edge(i,j+n,INF,v[i][j]);
            }
        }
        mincostmaxflow();
        printf("%d
    ",cost);
        init();
        for(int i=1;i<=n;i++){
            add_edge(sp,i,a[i],0);
        }
        for(int i=1;i<=m;i++){
            add_edge(i+n,ep,b[i],0);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                add_edge(i,j+n,INF,-v[i][j]);
            }
        }
        mincostmaxflow();
        printf("%d
    ",-cost);
        return 0;
    }
    
  • 相关阅读:
    第二章初识MySQL
    第一章 数据库
    Java&SQL7
    Java&SQL
    Java&SQL6
    Java&SQL5
    Java&SQL4
    Java&SQL3
    Java&SQL2
    博客地址已搬迁
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11348138.html
Copyright © 2011-2022 走看看