1. 程式人生 > >【最大流 模板題 EdmondsKarp】HDU

【最大流 模板題 EdmondsKarp】HDU

Problem Description

給你m,n分別代表m條邊,n個點。接下來給你m條邊,每條邊u,v,w。u->v流量的容量為w。有重邊

思路:模板題,所以給幾個模板 時間複雜度O(F*|E|),F 為最大流量,E 為邊的個數

EdmondsKarp-dfs-vector實現

//dfs實現
#include<bits/stdc++.h>
using namespace std;
const int N = 1000;
const int inf = 0x3f3f3f3f;
struct node
{
    int to, cap, rev;//終點,容量,終點到起點的下標( a[temp.to][temp.rev].cap就代表反向邊 )
}; vector<node> a[N];//用vector存圖 int vis[N]; void add(int u, int v, int w)//存邊 { a[u].push_back((node){v, w, a[v].size()}); a[v].push_back((node){u, 0, a[u].size() - 1}); } int dfs(int s, int t, int f) { if(s == t) return f;//到達了終點返回 vis[s] = 1;//標記 for(int i = 0; i < a[s].size(); i++) { node &temp = a[s][i];//因為要改變圖的邊,所以取地址
if(!vis[temp.to] && temp.cap > 0)//沒有走過的點,並且容量不為0 { int d = dfs(temp.to, t, min(f, temp.cap));//d為限制流量。核心min(f, temp.cap); if(d > 0)//回溯的過程中,如果d>0,代表找到了增廣路 { temp.cap -= d;//正向邊 -d a[temp.to][temp.rev].cap += d;//反向邊 +d
return d;//繼續回溯 } } } return 0; } int max_flow(int s, int t) { int flow = 0;//最大流 for(;;){ memset(vis, 0, sizeof(vis)); int d = dfs(s, t, inf);//搜增廣路,得到這條增廣路上限制容量 if(d == 0) return flow;//如果為0代表搜不到,直接返回輸出 flow += d;//搜到了,就疊加到最大流 } } int main() { int n, m, u, v, w; while(~scanf("%d %d", &m, &n)) { memset(a, 0, sizeof(a));//初始化 while(m--) { scanf("%d %d %d", &u, &v, &w); add(u, v, w); } printf("%d\n", max_flow(1, n)); } return 0; }

EdmondsKarp-dfs-前向星實現

#include<bits/stdc++.h>
using namespace std;
#define mm 250
struct node
{
    int to, w, next;
};
node Map[2 * mm];
int vis[mm], head[mm];
void add(int u, int v, int w, int &cnt)
{
    Map[cnt].to = v;
    Map[cnt].w = w;
    Map[cnt].next = head[u];
    head[u] = cnt++;
    Map[cnt].to = u;
    Map[cnt].w = 0;
    Map[cnt].next = head[v];
    head[v] = cnt++;
}
int dfs(int s, int t, int f)
{
    vis[s] = 1;
    if(s == t) return f;
    for(int i = head[s]; ~i; i = Map[i].next)
    {
        int to = Map[i].to, &w = Map[i].w;
        if(!vis[to] && w > 0)
        {
            int d = dfs(to, t, min(f, w));
            if(d > 0)
            {
                w -= d;
                Map[i^1].w += d;//反向邊表達
                //下標0是正向1就是反向。1^1=0,0^1=1;其他都和vector一致
                return d;
            }
        }
    }
    return 0;
}
int EK(int s, int t)//求最大流
{
    int Max_flow = 0, d;
    for(;;)
    {
        memset(vis, 0, sizeof(vis));
        d = dfs(s, t, 0x3f3f3f3f);
        if(d == 0) return Max_flow;//找不到增廣路
        Max_flow += d;
    }
}
int main()
{
    int n, m, u, v, w;
    while(~scanf("%d %d", &m, &n))
    {
        int cnt = 0;
        memset(head, -1, sizeof(head));
        while(m--)
        {
            scanf("%d %d %d", &u, &v, &w);//前向星
            add(u, v, w, cnt);
        }
        printf("%d\n", EK(1, n));
    }
    return 0;
}

EdmondsKarp-bfs實現

//BFS實現
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
const int inf = 0x3f3f3f3f;
int Map[N][N], Pre[N], Min_flow[N];//鄰接矩陣存邊,記錄路徑,記錄限制流量
int bfs(int s, int t)
{
    memset(Pre, -1, sizeof(Pre));//初始化
    queue<int> q;
    Min_flow[s] = inf;//一開始限制流量是無窮
    Pre[s] = 0;
    q.push(s);
    while(!q.empty())
    {
        s = q.front(); q.pop();
        if(s == t) break;//到達終點、找到一條增廣路;
        for(int i = 1; i <= t; i++)
        {
            if(Pre[i] == -1 && Map[s][i] > 0)//沒走過的點,容量大於0的點
            {
                //求限制流量
                Min_flow[i] = min(Min_flow[s], Map[s][i]);
                Pre[i] = s;//記錄路徑
                q.push(i);//入佇列
            }
        }
    }
    if(Pre[t] == -1) return -1;//代表沒有找到增廣路
    else return Min_flow[t];//找到了返回限制流量
}
int Ek(int s, int t)
{
    int Max_flow = 0, flow;//最大流,限制流量
    while((flow = bfs(s, t)) != -1)//如果為-1代表搜不到增廣路
    {
        Max_flow += flow;//更新最大流
        int u = t;
        while(u != 0)//增廣路 路徑上的邊,正向-flow,反向+flow
        {
            Map[Pre[u]][u] -= flow;
            Map[u][Pre[u]] += flow;
            u = Pre[u];
        }
    }
    return Max_flow;
}
int main()
{
    int m, u, v, w, n;
    while(~scanf("%d %d", &m, &n))
    {
        memset(Map, 0, sizeof(Map));
        while(m--)
        {
            scanf("%d %d %d", &u, &v, &w);
            Map[u][v] += w; //有重邊
        }
        printf("%d\n", Ek(1, n));
    }
    return 0;
}