标签:没有 href resize arp 大小 最大 基本 邻接矩阵 图论
本文参考以下文章
在图论中,网络流被定义为一个有向图,其中包含一个起点Source和一个终点Target,以及几条连接各顶点的边。每条边都有各自的容量Capacity,这是边所能允许的最大流量
网络流中的流量\(f\)应满足如下条件
最大流:网络允许从源Source流向终点Target的最大流量
下面介绍Ford-Fulkerson Algorithm(若使用BFS,则又称为Edmonds-Karp Algorithm)来解决此问题
Ford-Fulkerson Algorithm需要两个辅助工具
残差网络表示图中每条边剩余可允许通过的流量构成的图,以下图为例
若在Path:S-A-C-D-T上的所有边都有6单位的流量,那么这些边,\(edge(S,A)\)、\(edge(A,C)\)、\(edge(C,D)\)、\(edge(D,T)\)的剩余容量都应该减6。例如,\(edge(S,A)\)只能容纳3单位的流量,\(edge(C,D)\)只能容纳1单位的流量
若\(edge(x,y)\)上有\(f(x,y)\)单位的流量流过,则\(edge(x,y)\)上的residual capacity定义为:
Residual Networks也是一个有向图,其中:
最关键的是,若\(edge(A,C)\)上有6单位的流量流过\(f(A,C)=6\),那么在其Residual Networks上,会相应产生出一条顶点C指向顶点A的边\(edge(C,A)\),并具有6单位的residual capacity\(c_f(C,A)=6\)
这样做有什么意义?可以用如果想要重新配置流量方向来理解
举例来说,假设现在恢复到初始状态(没有任何流量流过),现在有2单位的流量经过Path:S-C-A-B-T,但是由于并不存在从顶点C指向顶点A的\(edge(C,A)\),因此\(c(C,A)=0\)。假设有6单位的流量从顶点A流向顶点C(如上图所示),那么现在就可以从\(edge(A,C)\)上把2单位的流量收回,从而分配到\(edge(A,B)\)上,而\(edge(A,C)\)上,就只剩下4单位的流量,最后结果如下图左所示,此时的Residual Networks如下图右所示
下图是从网上找到的另一个例子
在Residual Networks里,所有能够从源Source走到终Target的路径,也就是所有能够增加流量的路径,就称为Augmenting Paths(增广路径)
以上图为例,Augmenting Paths有很多种可能,例如
综上
flow/capacity
的图上找
讲完上面两个概念,下面讲解Ford-Fulkerson Algorithm算法
BFS()
寻找,确保每次找到的Augmenting Paths一定经过最少的edge以上图为例,寻找Maximum Flow的步骤如下
flow = 0
初始化residual Networksbfs()
找到从S到T且edge最少的Path:S-A-B-T
bfs()
找到的可能有三条最短Path,这里就以S-A-B-T为例bfs()
找到从S*到T且edge最少的Path:S-C-D-T观察Path:S-C-D-T上的edge,发现\(edge(C,D)\)具有最小的residual capacity \(c_f(C,D)=7\),所以update:总flow增加7
更新edge的residual capacity
接着重复上述步骤:更新Residual Networks,寻找Augmenting Paths
完整代码如下
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class Graph {
private:
int num_vertex; //顶点
vector<vector<int>> map; // 邻接矩阵
public:
Graph():num_vertex(0){};
Graph(int n);
void AddEdge(int from, int to, int capacity);
void FordFulkerson(int s, int t);
bool BfsFindExistingPath(vector<vector<int>> graph, int* predecessor, int s, int t);
int MinCapacity(vector<vector<int>> graph, int* predecessor, int t);
};
Graph::Graph(int n):num_vertex(n) {
map.resize(num_vertex);
for (int i = 0; i < num_vertex; i++)
map[i].resize(num_vertex);
}
bool Graph::BfsFindExistingPath(vector<vector<int>> graph, int* predecessor, int s, int t) {
int visited[num_vertex];
for (int i = 0; i < num_vertex; i++) {
visited[i] = 0; // 0 表示没有访问过
predecessor[i] = -1;
}
queue<int> queue;
queue.push(s);
visited[s] = 1; // 1 表示访问过
while (!queue.empty()) {
int vertex = queue.front(); queue.pop();
for (int j = 0; j < num_vertex; j++) {
if (graph[vertex][j] != 0 && visited[j] == 0) {
queue.push(j);
visited[j] = 1;
predecessor[j] = vertex;
}
}
}
return (visited[t] == 1); // 若t被访问过,表示有path从s到t
}
int Graph::MinCapacity(vector<vector<int>> graph, int* predecessor, int t) {
int min = 0x3f3f3f; // 确保min会更新,假设graph上的capacity都小于0x3f3f3f
// 用predecessor[idx]和idx表示一条edge
// 找到 从s到t 的path中,capacity最小的值,存入min
for (int idx = t; predecessor[idx] != -1; idx = predecessor[idx])
if (graph[predecessor[idx]][idx] != 0 && graph[predecessor[idx]][idx] < min)
min = graph[predecessor[idx]][idx];
return min;
}
void Graph::FordFulkerson(int s, int t) {
vector<vector<int>> graphResidual(map);
int maxflow = 0;
int predecessor[num_vertex];
// bfs find augmeting path
while (BfsFindExistingPath(graphResidual, predecessor, s, t)) {
int min_capacity = MinCapacity(graphResidual, predecessor, t);
maxflow = maxflow + min_capacity;
for (int y = t; y != s; y= predecessor[y]) {
// update residual graph
int x = predecessor[y];
graphResidual[x][y] -= min_capacity;
graphResidual[y][x] += min_capacity;
}
}
cout << "Maximum Flow: " << maxflow << endl;
}
void Graph::AddEdge(int from, int to, int capacity) {
map[from][to] = capacity;
}
int main() {
Graph g(6);
g.AddEdge(0, 1, 9);g.AddEdge(0, 3, 9);
g.AddEdge(1, 2, 3);g.AddEdge(1, 3, 8);
g.AddEdge(2, 4, 2);g.AddEdge(2, 5, 9);
g.AddEdge(3, 2, 7);g.AddEdge(3, 4, 7);
g.AddEdge(4, 2, 4);g.AddEdge(4, 5, 8);
g.FordFulkerson(0, 5); // 指定source为0,target为5
return 0;
}
标签:没有 href resize arp 大小 最大 基本 邻接矩阵 图论
原文地址:https://www.cnblogs.com/mathor/p/12416573.html