我明白了,
余量网络 名如其名
比如你f/c=3/5
那么正边2,reverse edge3,加起来是5
在这个你建的新图上找s到t的路径
然后path的最小边权叫delta
给流图的对应path的每条边e都加流 delta,或者 反边减delta (反边的情况)
得到新的流,重复
直到余量网络没有s到t的路径
(最大流-最小割定理也行)
求最小费用流
找个最大流,
然后
建立个新图
比如这条边的性质 容量,代价= 6,3,跑着2的流
那么正向边标4,3
反向标 2,-3
新图上找 负环(负环的代价和为负)
然后min{a_1}
流加上这个
流调整了
重复
直到新图上找不到 负环(负环的代价和为负)
不断调整f得到最大流
我吐了都,要想手撕个算法首先还得理解一些定义
我找了个课件边看边学
https://www.cs.princeton.edu/~wayne/kleinberg-tardos/pdf/07NetworkFlowI.pdf
定义大概就这些
Def. The bottleneck capacity of an augmenting path P is the minimum residual capacity of any edge in P
伪代码
其中,AUGMENT()如下
自己做slide里的quiz
搬运别人的代码
// Copyright srcmake 2018.
// C++ Example Ford Fulkerson Algorithm
/* Ford Fulkerson Algorithm:
// 0. Initialize an adjacency matrix to represent our graph.
// 1. Create the residual graph. (Same as the original graph.)
// 2. Create an default parent vector for BFS to store the augmenting path.
// 3. Keep calling BFS to check for an augmenting path (from the source to the sink...
// 4. Find the max flow through the path we found.
// 5. Update the residual capacities of the edges and reverse edges.
// 6. Add this path's flow to our total max flow so far.
*/
// The example graph: https://www.srcmake.com/uploads/5/3/9/0/5390645/maxflow_1_orig.jpg
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
//////////////////////////////////////////////////////////////////////////////////////////////
// See the picture here: https://www.srcmake.com/uploads/5/3/9/0/5390645/adjmatrix_1_orig.jpg
vector< vector<int> > FormAdjMatrix()
{
// Our adjacency list.
vector< vector<int> > adjMatrix;
const int n = 6;
// Initialize our matrix to all 0s.
for(int i = 0; i < n; i++)
{
vector<int> row;
adjMatrix.push_back(row);
for(int j = 0; j < n; j++)
{
adjMatrix[i].push_back(0);
}
}
// First number is the vertex, second is the edge capacity.
adjMatrix[0][1] = 15;
adjMatrix[0][2] = 12;
adjMatrix[1][2] = 9;
adjMatrix[1][3] = 11;
adjMatrix[2][1] = 5;
adjMatrix[2][4] = 13;
adjMatrix[3][2] = 9;
adjMatrix[3][5] = 25;
adjMatrix[4][3] = 8;
adjMatrix[4][5] = 6;
// Our graph is now represented as an adjacency list.
return adjMatrix;
}
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// A special BFS version that returns true if there's a path from source to sink.
bool BFS(vector< vector<int> > &resAdjMatrix, int &source, int &sink, vector<int> &parent)
{
// Create an array for all nodes we visited. Initialized to false.
int n = resAdjMatrix.size();
bool visited[n] = { false };
// Create a queue to check each node.
queue<int> q;
// Push our source into the queue and mark it as visited. It has no parent.
q.push(source);
visited[source] = true;
parent[source] = -1;
// Keep visiting vertices.
while(q.empty() == false)
{
int u = q.front();
q.pop();
// Check all of u's friends.
for(int i = 0; i < n; i++)
{
int v = i;
int capacity = resAdjMatrix[u][v];
// We find a neighbor that hasn't been visited, and the capacity is bigger than 0.
if(visited[v] == false && capacity > 0)
{
// Push the neighbor onto the queue, mark it's parent, and mark it as visited.
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
}
// If the sink got visited, then we found a path to it.
if(visited[sink] == true)
{ return true; }
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// Use the Ford Fulkerson algorithm. Return the max flow.
int FordFulkerson(vector< vector<int> > &adjMatrix, int &source, int &sink)
{
int maxflow = 0;
// 1. Create the residual graph. (Same as the original graph.)
vector< vector<int> > resAdjMatrix;
int n = adjMatrix.size();
for(int i = 0; i < n; i++)
{
vector<int> row;
resAdjMatrix.push_back(row);
for(int j = 0; j < adjMatrix[i].size(); j++)
{
resAdjMatrix[i].push_back(adjMatrix[i][j]);
}
}
// 2. Create an empty parent array for BFS to store the augmenting path.
vector<int> parent;
for(int i = 0; i < n; i++)
{
parent.push_back(-1);
}
// 3. Keep calling BFS to check for an augmenting path (from the source to the sink...
while(BFS(resAdjMatrix, source, sink, parent) == true)
{
// 4. Find the max flow through the path we just found.
int pathflow = 10000007;
// Go through the path we just found. Iterate through the path.
int v = sink;
while(v != source)
{
int u = parent[v]; // The parent.
// Update the pathflow to this capacity if it's smaller
int capacity = resAdjMatrix[u][v];
pathflow = min(pathflow, capacity);
// Setup for the next edge in the path.
v = u;
}
// 5. Update the residual capacities of the edges and reverse edges.
v = sink;
while(v != source)
{
int u = parent[v]; // The parent.
// Update the capacities.
resAdjMatrix[u][v] -= pathflow;
resAdjMatrix[v][u] += pathflow;
// Setup for the next edge in the path.
v = u;
}
// 6. Add this path's flow to our total max flow so far.
maxflow += pathflow;
}
return maxflow;
}
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
cout << "Program started.\n";
// Create our adjacency list.
vector< vector<int> > adjMatrix = FormAdjMatrix();
// Call FordFulkerson to get the max flow from the source to the sink.
int source = 0;
int sink = 6;
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 6; j++)
{
int source = i;
int sink = j;
if(i == j) { continue; }
cout << "The max flow from " << source << " to " << sink << " is: ";
cout << FordFulkerson(adjMatrix, source, sink) << endl;
}
cout << endl;
}
cout << "Program ended.\n";
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////