最大流 和 最小花费最大流

最大流

int n, m; // 顶点和边数
int flow[100][100], cap[100][100]; // 流量和容量
int p[100]; // 上一个节点
int a[100]; // 从s到此节点最小残量

void read(){
	cin >> n >> m;
	for(int i = 0; i < m; i++){
		int x, y, z;
		cin >> x >> y >> z;
		cap[x][y] = z;
	}
}

int max_flow(int s, int t){
	memset(flow, 0, sizeof(flow));
	int f = 0;
	while(true){
		memset(a, 0, sizeof(a));
		a[s] = INF;
		queue<int> q;
		q.push(s);
		while(!q.empty()){ // BFS,找增广路
			int u = q.front();
			q.pop();
			for(int i = 0; i < n; i++){
				if(!a[i] && cap[u][i] > flow[u][i]){ // 找到满足的顶点
					p[i] = u;
					q.push(i);

					if(cap[u][i] - flow[u][i] < a[u]){
						a[i] = cap[u][i] - flow[u][i];
					}else{
						a[i] = a[u];
					}
				}
			}
		}
		if(a[t] == 0) // 找不到,已是最大流
			break;
		for(int u = t; u != s; u = p[u]){ // 从t往回走
			flow[p[u]][u] += a[t];
			flow[u][p[u]] -= a[t];
		}
		f += a[t]; // 更新从s流出的流量
	}

	return f;
}

最小花费最大流

int n, m; // 顶点和边数
int flow[100][100], cap[100][100], cost[100][100]; // 流量、容量、单位花费
int p[100]; // 上一个节点

void read(){
	cin >> n >> m;
	for(int i = 0; i < m; i++){
		int x, y, z, c;
		cin >> x >> y >> z >> c;
		cap[x][y] = z;
		cost[x][y] = c;
	}
}

pair<int, int> min_cost_max_flow(int s, int t){
	memset(flow, 0, sizeof(flow));
	int c = 0, f = 0;
	while(true){
		int d[100]; // s到节点的最短路
		for(int i = 0; i < n; i++)
			d[i] = INF;
		d[s] = 0;

		bool inq[100]; // 节点是否在队列
		memset(inq, 0, sizeof(inq));

		queue<int> q;
		q.push(s);
		while(!q.empty()){ // 因cost可能有负,用bellman-ford算法
			int u = q.front();
			q.pop();
			inq[u] = false;
			for(int v = 0; v < n; v++){
				if(cap[u][v] > flow[u][v] && d[u] + cost[u][v] < d[v]){
					d[v] = d[u] + cost[u][v];
					p[v] = u;
					if(!inq[v]){
						q.push(v);
						inq[v] = true;
					}
				}
			}
		}

		if(d[t] == INF) // 已经是最小花费最大流
			break;
		int a = INF;
		for(int u = t; u != s; u = p[u]){ // 求出s到t最小的残量
			if(cap[p[u]][u] - flow[p[u]][u] < a){
				a = cap[p[u]][u] - flow[p[u]][u];
			}
		}

		for(int u = t; u != s; u = p[u]){ // 增广
			flow[p[u]][u] += a;
			flow[u][p[u]] -= a;
		}
		f += a;
		c += a * d[t];
	}
	return make_pair(f, c);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值