最小费用最大流算法

反复寻找费用最小路径,然后在该路径上使流量增大;寻找最小费用路径时,不考虑剩余容量为 0 的边;虽然网络流图是有向图,但是为了寻找包含反向边的路径,对每条正向边都有可能生成出反向边(当正向边上有流量时,就有容量等于流量的反向边);

NetworkFlowGraph.h 类头文件:

/*
 * NetworkFlowGraph.h
 *
 *  Created on: 2013-1-22
 *      Author: qichi
 */

#ifndef NETWORKFLOWGRAPH_H_
#define NETWORKFLOWGRAPH_H_

#define MAXVAL (1.0e8)
#define MINVAL (1.0e-6)

class NetworkFlowGraph {
private:
	int m_num;			// number of vertex
	int m_s;			// source point
	int m_t;			// destination point

	double ** m_cap;	// the max capability of an edge
	double ** m_price;	// the unit price of an edge
	double ** m_vol;	// the surplus capability of an edge

	int *m_prev;		// the previous point
	double *m_dist;		// the distance from s to each point

	double m_cost;		// current cost
	double m_flow;		// current flow

public:
	NetworkFlowGraph(int n, int s, int t);
	virtual ~NetworkFlowGraph();

public:
	void insert(int i, int j, int cap, int price);
	bool min_cost_path(double &price);
	bool min_cost_flow(double desired, double &maxflow, double &mincost);
	void min_cost_max_flow(double &maxflow, double &mincost);
	void printMatrix();
	void printPath();
};

#endif /* NETWORKFLOWGRAPH_H_ */

NetworkFlowGraph.cpp 类实现:

/*
 * NetworkFlowGraph.cpp
 *
 *  Created on: 2013-1-22
 *      Author: qichi
 */

#include "NetworkFlowGraph.h"
#include <string.h>
#include <iostream>

NetworkFlowGraph::NetworkFlowGraph(int n, int s, int t) {

	m_num = n;
	m_s = s;
	m_t = t;

	m_cap = new double*[n];
	m_cap[0] = new double[n*n];

	m_price = new double*[n];
	m_price[0] = new double[n*n];

	m_vol = new double*[n];
	m_vol[0] = new double[n*n];

	for ( int i=1; i<n; i++ ) {
		m_cap[i] = m_cap[i-1]+n;
		m_price[i] = m_price[i-1]+n;
		m_vol[i] = m_vol[i-1]+n;
	}

	m_prev = new int[n];
	m_dist = new double[n];

	m_cost = 0;
	m_flow = 0;

	memset(m_cap[0],0,n*n*sizeof(double));
	memset(m_price[0],0,n*n*sizeof(double));
	memset(m_vol[0],0,n*n*sizeof(double));

}

NetworkFlowGraph::~NetworkFlowGraph() {
	delete m_cap[0];
	delete m_price[0];
	delete m_vol[0];
	delete m_cap;
	delete m_price;
	delete m_vol;
}

void NetworkFlowGraph::insert(int i, int j, int cap, int price) {
	if ( i < m_num && j < m_num ) {
		m_cap[i][j] = cap;
		m_vol[i][j] = cap;
		m_price[i][j] = price;
		m_price[j][i] = -price;
	}
}

bool NetworkFlowGraph::min_cost_path(double &price) {

	for ( int i=0; i<m_num; i++ ) {
		m_dist[i] = MAXVAL;
		m_prev[i] = -1;
	}
	m_dist[m_s] = 0;

	bool updated = false;
	do {
		updated = false;
		for ( int i=0; i<m_num; i++ ) {
			if ( m_dist[i] < MAXVAL - MINVAL ) {
				for ( int j=0; j<m_num; j++ ) {
					// only consider edges with surplus volume
					if ( m_vol[i][j]>MINVAL ) {
						if ( m_dist[j] > m_dist[i] + m_price[i][j] ) {
							m_dist[j] = m_dist[i] + m_price[i][j];
							m_prev[j] = i;
							updated = true;
						}
					}
				}
			}
		}
	} while (updated);

	price = m_dist[m_t];
	return (m_prev[m_t]!=-1);
}

bool NetworkFlowGraph::min_cost_flow(double desired, double &maxflow, double &mincost){

	maxflow = 0;
	mincost = 0;

	bool min_path_exist;
	do {
		double price;
		// find a path with min cost
		min_path_exist = min_cost_path(price);
		if ( min_path_exist ) {

			// go through the path to determine flow allowed
			int q = m_t, p = m_prev[q];
			double flow = MAXVAL;
			while ( p!=-1 ) {
				if ( flow > m_vol[p][q] ) flow = m_vol[p][q];
				q = p;	p = m_prev[q];
			}

			// if flow allowed is more than required
			if ( flow > desired - maxflow )
				flow = desired - maxflow;

			// adjust the volume matrix
			q = m_t, p = m_prev[q];
			while ( p!=-1 ) {
				m_vol[p][q] -= flow;
				m_vol[q][p] += flow;
				q = p;	p = m_prev[q];
			}

			// accumulate max flow and cost
			maxflow += flow;
			mincost += flow*price;
		}
	} while ( min_path_exist && maxflow < desired - MINVAL );

	return ( maxflow >= desired - MINVAL );

}

void NetworkFlowGraph::min_cost_max_flow(double &maxflow, double &mincost) {
	double desired = MAXVAL;
	min_cost_flow(desired,maxflow,mincost);
}

void NetworkFlowGraph::printMatrix() {
	std::cout << std::endl;
	std::cout << "capability matrix:" << std::endl;
	for ( int i=0; i<m_num; i++ ) {
		for ( int j=0; j<m_num; j++ ) {
			std::cout << m_cap[i][j] << "   ";
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
	std::cout << "price matrix:" << std::endl;
	for ( int i=0; i<m_num; i++ ) {
		for ( int j=0; j<m_num; j++ ) {
			std::cout << m_price[i][j] << "   ";
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
	std::cout << "current volume matrix:" << std::endl;
	for ( int i=0; i<m_num; i++ ) {
		for ( int j=0; j<m_num; j++ ) {
			std::cout << m_vol[i][j] << "   ";
		}
		std::cout << std::endl;
	}
	std::cout << std::endl;
}

void NetworkFlowGraph::printPath() {
	if ( m_prev[m_t] > MAXVAL - MINVAL ) {
		std::cout << "no path" << std::endl;
	} else {
		std::cout << "min cost path is : ";
		int p = m_t;
		while ( p!=-1 ) {
			std::cout << p << "<-";
			p = m_prev[p];
		}
		std::cout << m_dist[m_t] << std::endl;
	}
}

测试:

//============================================================================
// Name        : MinCostFlow.cpp
// Author      : Qichi
// Version     :
// Copyright   : Copyright QiChi
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include "NetworkFlowGraph.h"
using namespace std;

int main() {
	double flow, cost;
	NetworkFlowGraph *inst = new NetworkFlowGraph(5,0,4);
	inst->insert(0,1,10,4);
	inst->insert(0,2,8,1);
	inst->insert(2,1,5,2);
	inst->insert(2,3,10,3);
	inst->insert(1,3,2,6);
	inst->insert(1,4,7,1);
	inst->insert(3,4,4,2);
	inst->min_cost_max_flow(flow, cost);
	cout << flow << ":" << cost << endl;
	delete inst;
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值