講解
模板題目鏈接 洛谷P3376
模板來自算法競賽入門經典(第2版)--劉汝佳
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int maxn = 100010;
struct edge //記錄這條邊的信息
{
int from, to, cap, flow; //起點,終點,容量,流量
edge(int a, int b, int c, int d) : from(a), to(b), cap(c), flow(d){}//初始化
};
int n, m;
vector<edge> e; //存儲邊的信息
vector<int> g[maxn]; //鄰接表存圖,這裏存的是邊在e裏的編號
int a[maxn]; //記錄點目前的流量
int p[maxn]; //記錄路徑,p[i] 即由s到t路徑上點i的前一個點,
void init(int n) //初始化清空
{
for (int i = 0; i <= n;i++)
g[i].clear();
e.clear();
}
void AddEdge(int from,int to,int cap)
{
e.push_back(edge(from, to, cap, 0)); //正向加邊
e.push_back(edge(to, from, 0, 0)); //反向加邊
m = e.size();
g[from].push_back(m - 2); //正向存圖
g[to].push_back(m - 1); //反向存圖
}
int MaxFlow(int s,int t)
{
int ans = 0; //最終返回的答案
while (true)
{
memset(a, 0, sizeof(a));
queue<int> q; //BFS循環隊列
q.push(s);
a[s]=INF; //源點水流量設爲無窮
while(!q.empty())
{
int x = q.front(); //取出當前流經的點
q.pop();
for (int i = 0; i < g[x].size();i++) //遍歷當前點可以流到的點
{
edge now = e[g[x][i]];
if(a[now.to] == 0 && now.cap > now.flow)
//如果當前點沒有被水流到過,並且容量大於流量
{
p[now.to] = g[x][i]; //記錄前驅點
a[now.to] = min(a[x], now.cap - now.flow);
//當前點的流量爲上一個點的流量和還可以流的流量的最小值
q.push(now.to);//放入隊列
}
}
if(a[t]!=0)//如果水流已經流到終點,結束此次循環
break;
}
if(a[t]==0) //如果沒有找到增廣路,退出循環
break;
for (int i = t; i != s;i=e[p[i]].from) //回溯找到水流的路徑
{
e[p[i]].flow += a[t]; //把這條路徑上的流量加上
e[p[i]^1].flow -= a[t]; // 反向邊的流量要減少,減少後反向邊的容量就會大於流量,就相當於給了水流一個退回去的機會
}
ans += a[t];
}
return ans;
}
int main()
{
int mm,start, ed;
cin >> n >> mm >> start >> ed;
init(n);
for (int i = 0; i < mm; i++)
{
int from, to, cap;
cin >> from >> to >> cap;
AddEdge(from, to, cap);
}
cout << MaxFlow(start, ed) << endl;
return 0;
}