反复寻找费用最小路径,然后在该路径上使流量增大;寻找最小费用路径时,不考虑剩余容量为 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;
}