【网络流24题-洛谷-P4015】运输问题(网络费用流量、最小费用最大流)

题目描述

WW 公司有 mm 个仓库和 nn 个零售商店。第 ii 个仓库有 a_iai​ 个单位的货物;第 jj 个零售商店需要 b_jbj​ 个单位的货物。

货物供需平衡,即\sum\limits_{i=1}^{m}a_i=\sum\limits_{j=1}^{n}b_ji=1∑m​ai​=j=1∑n​bj​。

从第 ii 个仓库运送每单位货物到第 jj 个零售商店的费用为 c_{ij}cij​​​ 。

试设计一个将仓库中所有货物运送到零售商店的运输方案,使总运输费用最少。

输入格式

第 11 行有 22 个正整数 mm 和 nn,分别表示仓库数和零售商店数。

接下来的一行中有 mm 个正整数 a_iai​,表示第 ii 个仓库有 a_iai​个单位的货物。

再接下来的一行中有 nn 个正整数 b_jbj​,表示第 jj 个零售商店需要 b_jbj​ 个单位的货物。

接下来的 mm 行,每行有 nn 个整数,表示从第 ii 个仓库运送每单位货物到第 jj 个零售商店的费用 c_{ij}cij​。

输出格式

两行分别输出最小运输费用和最大运输费用。

输入输出样例

输入 #1复制

2 3
220 280
170 120 210
77 39 105
150 186 122

输出 #1复制

48500
69140

说明/提示

1 \leq n, m \leq 1001≤n,m≤100

思路:

源点连向仓库,流量为库存量,费用为0。

商店连向汇点,流量为销售量,费用为0。

任意的仓库和商店连边,流量为无穷,费用为对应的费用。

 

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<vector>
#include<unordered_map>
#define mod (1000000007)
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 5;
const int inf = 0x3f3f3f3f;
struct node {
    int v,f,w,nxt;
} e[50005<<2];
int n,m,N;
int head[MAX],d[MAX],vis[MAX],tot=1,p[MAX];
void add(int u,int v,int f,int cost=0) {
    e[++tot].v = v;e[tot].f = f;e[tot].w = cost;e[tot].nxt = head[u];head[u] = tot;
    e[++tot].v = u;e[tot].f = 0; e[tot].w = -cost;e[tot].nxt = head[v];head[v] = tot;
}
bool bfs(int s,int t) {
    for(int i = 0; i<=N; i++) d[i]=inf,vis[i]=0;
    d[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty()) {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u]; ~i; i=e[i].nxt) {
            int j=e[i].v;
            if(e[i].f&&d[j]>d[u]+e[i].w) {
                d[j]=d[u]+e[i].w;
                p[j]=i;
                if(!vis[j])vis[j]=1,q.push(j);
            }
        }
    }
    return d[t]<inf;
}
int MCMF(int s,int t,int &flow) {
    int ans=0;
    while(bfs(s,t)) {
        int x=t,f=inf;
        while(x!=s) {
            f = min(f,e[p[x]].f),x=e[p[x]^1].v;
        }
        flow += f;
        ans+=1LL*d[t]*f;
        x=t;
        while(x!=s) {
            e[p[x]].f-=f,e[p[x]^1].f+=f;
            x=e[p[x]^1].v;
        }
    }
    return ans;
}
int a[120],b[120],c[120][120];
int main() {
    scanf("%d%d",&m,&n);
    int st=0,ed=m+n+1,fl=0;N=ed;
    for(int i=0;i<=m+n+1;i++) head[i]=-1;
    for(int i=1;i<=m;i++){
    	scanf("%d",&a[i]);
		add(st,i,a[i],0);
	}
	for(int i=1;i<=n;i++){
    	scanf("%d",&b[i]);
		add(i+m,ed,b[i],0);
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&c[i][j]);
			add(i,j+m,inf,c[i][j]);
		}
	}
	int ans=MCMF(st,ed,fl);//最小费用最大流
	
	tot=1;//本次代码赋初值为1 
	for(int i=0;i<=m+n+1;i++) head[i]=-1;
    for(int i=1;i<=m;i++){
		add(st,i,a[i],0);
	}
	for(int i=1;i<=n;i++){
		add(i+m,ed,b[i],0);
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=n;j++){
			add(i,j+m,inf,-c[i][j]);
		}
	}
	int ans2=MCMF(st,ed,fl);
	
	printf("%d\n%d\n",ans,-ans2);
	
	return 0 ;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值