最大流的增廣路算法

講解

模板題目鏈接 洛谷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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章