博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 【网络流24题】运输问题

题面

 

解析

这也就是一道费用流的模板题啊!

将S与仓库连边,流量为存货,费用为0,

商店与T连边,流量为需求,费用为0,

(S,T反过来也可以)。

然后把每个仓库与商店连边,

流量为INF,费用为c[i][j],

再spfa+EK求最小费用最大流,最大费用最大流即可(应该不需要证明吧)。

 

 

上AC代码:

#include<bits/stdc++.h>
using namespace std;

inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

const int INF=0x3f3f3f3f;
struct node{
    int next,to,w,v;
}e[100001];
int n,m,s,t;
int head[100001],cnt=1;
int a[10001],b[10001],c[1001][1001];
int pre[100001],d[100001],inq[100001],id[100001];

void add(int x,int y,int v,int w){
    e[++cnt].to=head[x];
    e[cnt].next=y;
    e[cnt].v=v;
    e[cnt].w=w;
    head[x]=cnt;
}

bool minspfa(){
    memset(d,0x3f,sizeof(d));
    memset(pre,0,sizeof(pre));
    memset(inq,0,sizeof(inq));
    int que[100001]={0};
    int h=1,tail=1;
    que[1]=s;
    d[s]=0;
    while(h<=tail){
        int x=que[h];
        inq[x]=0;
        h++;
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;
            if(e[i].v&&d[k]>d[x]+e[i].w){

                pre[k]=x;
                id[k]=i;
                d[k]=d[x]+e[i].w;
                if(!inq[k]) que[++tail]=k;
                inq[k]=1;
            }
        }
    }
    return d[t]!=INF;
}

bool maxspfa(){
    memset(d,-0x3f,sizeof(d));
    memset(pre,0,sizeof(pre));
    memset(inq,0,sizeof(inq));
    int que[100001]={0};
    int h=1,tail=1;
    que[1]=s;
    d[s]=0;
    while(h<=tail){
        int x=que[h];
        inq[x]=0;
        h++;
        for(int i=head[x];i;i=e[i].to){
            int k=e[i].next;
            if(e[i].v&&d[k]<d[x]+e[i].w){

                pre[k]=x;
                id[k]=i;
                d[k]=d[x]+e[i].w;
                if(!inq[k]) que[++tail]=k;
                inq[k]=1;
            }
        }
    }
    return d[t]>-1044266559;
}


void EK1(){
    cnt=1;
    memset(head,0,sizeof(head));
    for(int i=1;i<=m;i++){
        add(s,i,a[i],0);
        add(i,s,0,0);
        for(int j=1;j<=n;j++){
            add(i,j+m,INF,c[i][j]);
            add(j+m,i,0,-c[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        add(i+m,t,b[i],0);
        add(t,i+m,0,0);
    }
    int cost=0;
    while(minspfa()){      
        int mi=INF;
        for(int i=t;i!=s;i=pre[i]){
            mi=min(mi,e[id[i]].v);
        }
        for(int i=t;i!=s;i=pre[i]){
            e[id[i]].v-=mi;
            e[id[i]^1].v+=mi;
        }
        cost+=mi*d[t];
    }
    printf("%d\n",cost);
}

void EK2(){
    cnt=1;
    memset(head,0,sizeof(head));
    for(int i=1;i<=m;i++){
        add(s,i,a[i],0);
        add(i,s,0,0);
        for(int j=1;j<=n;j++){
            add(i,j+m,INF,c[i][j]);
            add(j+m,i,0,-c[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        add(i+m,t,b[i],0);
        add(t,i+m,0,0);
    }
    int cost=0;
    while(maxspfa()){      
        int mi=INF;
        for(int i=t;i!=s;i=pre[i]){
            mi=min(mi,e[id[i]].v);
        }
        for(int i=t;i!=s;i=pre[i]){
            e[id[i]].v-=mi;
            e[id[i]^1].v+=mi;
        }
        cost+=mi*d[t];
    }
    printf("%d\n",cost);
    
}

int main(){
    m=read();n=read();
    s=m+n+1;t=m+n+2;
    for(int i=1;i<=m;i++){
        a[i]=read();
    }
    for(int i=1;i<=n;i++){
        b[i]=read();
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=n;j++){
            c[i][j]=read();
        }
    }
    EK1();
    EK2();
    return 0;
}

 

posted @ 2019-03-11 21:12  Hastin  阅读(184)  评论(0编辑  收藏  举报