洛谷p3381 最小费最大流模板 spfa + dinic

题目描述

如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。

输入格式

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。

输出格式

一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用。

输入输出样例

输入 #1复制

4 5 4 3
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5

输出 #1复制

50 280
#include<bits/stdc++.h>
const int maxn = 5e4 + 10;
int head[maxn];
int vis[maxn];
int dis[maxn];
int flow[maxn];
int pre[maxn];
int last[maxn];
int tot;
int n, m, s, t;
using namespace std;
struct node{
	int to;
	int next;
	int f;
	int w;
	node() {}
	node(int a, int b, int c, int d) : to(a), next(b), f(c), w(d) {}
}edge[maxn * 10];

void edgeadd(int a, int b, int c, int d){
	edge[tot] = node(b, head[a], c, d);
	head[a] = tot++;
	edge[tot] = node(a, head[b], 0, -d);
	head[b] = tot++;
}

void init(){
	memset(head, -1, sizeof(head));
	tot = 0;
}

void spfainit(){
	memset(vis, 0, sizeof(vis));
	memset(dis, 0X3f3f, sizeof(dis));
	memset(flow, 0x3f3f, sizeof(flow));
}

bool spfa(){
	spfainit();
	queue<int> q;
	q.push(s);
	pre[t] = -1;
	vis[s] = 1;
	dis[s] = 0;
	//flow[s] = 0;
	while(!q.empty()){
		int nw = q.front();
		q.pop();
		vis[nw] = 0;
		for(int i = head[nw]; i != -1; i = edge[i].next){
			int y = edge[i].to;
			int w = edge[i].w;
			int f = edge[i].f;
			if(f && dis[y] > dis[nw] + w){
				dis[y] = dis[nw] + w;
				flow[y] = min(flow[nw], f);
				pre[y] = nw;
				last[y] = i;
				if(!vis[y]){
					q.push(y);
					vis[y] = 1;
				}
			}
		}
	}
	return pre[t] != -1;
}

void dinic(){
	int maxflow = 0, minw = 0;
	while(spfa()){
	maxflow += flow[t];
	minw += flow[t] * dis[t];
		int x = t;
		while(x != s){
			edge[last[x]].f -= flow[t];
			edge[(last[x] ^ 1)].f += flow[t];
			x = pre[x];
		}
	}
	cout << maxflow << " " << minw << endl;
}
int main(){
	ios::sync_with_stdio(false);
	cin >> n >> m >> s >> t;
	init();
	for(int i = 1; i <= m; i++){
		int a, b, c, d;
		cin >> a >> b >> c >> d;
		edgeadd(a, b, c, d);
	}
	dinic();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值