网络流之最大流Ford-Fulkerson算法
最大流问题可以利用Ford-Fulkerson算法进行求解,其中Ford-Fulkerson算法求解步骤就是:构建出残余网络图,在残余网络图中寻找增广路径,利用增广路径中最小flow进行更新残余网络图,再寻找增广路径,以此往复,直到在残余网络图中找不到增广路径为止,这时候的totalflow就是整个网络图中的最大流。
#include"stdafx.h"
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 1e5;
const int INF = 1e9;
struct node {
int v;
int volume;//容量
int flow;//剩余流入量
};
vector<node> adj[maxn];//邻接表存储图
int vertexnum, edgenum;//顶点数、边数
bool vis[maxn] = { false };//
int minflow[maxn] = { 0 };//minflow[i]=k表示从s到达i这条增广路径中的最小flow为k
vector<int> path[maxn];//path[i]记录了从s到达结点i的增广路径序列
int bfs(int s, int t) {//广度优先bfs寻找增广路径
queue<int>q;
minflow[s] = INF;//
path[s].push_back(s);
q.push(s);
vis[s] = true;//标记顶点s已入队或者已被访问
bool flag = false;//标志是否有从s到t的增广路径
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < adj[u].size(); i++) {
int v = adj[u][i].v;
int flow = adj[u][i].flow;
if (vis[v] == false && flow>0) {//如果v未被访问且flow大于0
q.push(v);
vis[v] = true;
//更新到达v的路径【从s到达v的增广路径为:s到达u的路径再加上从u到达v的路径】
path[v] = path[u];
path[v].push_back(v);//将结点v加入到路径中
//
minflow[v] = min(minflow[u], flow);//更新增广路径上的最小流
if (v == t) {
while (!q.empty()) q.pop();//清空队列中的元素
flag = true;//标志有从s到t的增广路径
break;
}
}
}
}
if (flag == true) return minflow[t];//返回增广路径上的最小flow
else return -1;//如果没找到从s到t的增广路径,则返回-1
}
void updatenetflow(int k,vector<int> path) {//更新残余网络
int u = path.front();
for (int i = 1; i < path.size(); i++) {
int v = path[i];
for (int j = 0; j < adj[u].size(); j++) {
if (adj[u][j].v == v) {
adj[u][j].flow -= k;
break;
}
}
for (int j = 0; j < adj[v].size(); j++) {
if (adj[v][j].v == u) {
adj[v][j].flow += k;
break;
}
}
u = v;
}
}
int Ford_Fullkerson(int s, int t) {//最大流算法
int totalflow = 0;//从s到达t的最大网络流
int flow;
do {
for (int i = 0; i < vertexnum; i++) {//bfs之前将以下数据全部清空
while (!path[i].empty()) path[i].pop_back();
minflow[i] = 0;
vis[i] = false;
}
flow = bfs(s, t);//bfs进行寻找增广路径,并return增广路径中最小flow
if (flow != -1) {//如果找到增广路径
totalflow += flow;
updatenetflow(flow, path[t]);//更新残余网络
}
} while (flow != -1);
return totalflow;
}
int main() {
cin >> vertexnum >> edgenum;
int vertex1, vertex2, volume;
for (int i = 0; i < edgenum; i++) {
cin >> vertex1 >> vertex2 >> volume;//结点1,结点2,以及结点1到达结点2的传输的最大数据量
node N;
N.v = vertex2;
N.volume = volume;
N.flow = volume;
adj[vertex1].push_back(N);
N.v = vertex1;
N.flow = 0;
adj[vertex2].push_back(N);
}
int s, t;
cin >> s >> t;
cout << Ford_Fullkerson(s, t);
return 0;
}
---------------------------------------------------------------------------------------
bool dfs(int s, int t) {//深度优先遍历图寻找增广路径
if (s == t) {
path.push_back(s);//path数组中保存了从s到t的增广路径序列
return true;//找到从s到达t的增广路径,返回true
}
vis[s] = true;
path.push_back(s);
for (int i = 0; i < adj[s].size(); i++) {
int v = adj[s][i].v;
int flow = adj[s][i].flow;
if (vis[v] == false && flow>0) {
if (flow < miniflow) {
miniflow = flow;
}
bool flag = dfs(v, t);
if (flag == true) return true;//如果找到增广路径,则return返回,不需要再进行递归了
}
}
//回溯
vis[s] = false;
path.pop_back();
return false;//如果没找到,则return false
}
下一篇:
动态规划-最长递增子序列
