网络流之最大流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 }
下一篇:
动态规划-最长递增子序列