ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Ford-Fulkerson algorithm
    Algorithm/그래프 2020. 2. 10. 17:55
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    //네트워크 유량 문제를 해결하는 포드-폴커슨 알고리즘의 구현
     
    const int INF = 987654321;
    int V;
    //capacity[u][v] : u에서 v로 보낼수 있는 용량
    //flow[u][v] : u에서 v로 흘러가는 유량(반대 방향인 경우 음수)
    int capacity[MAX_V][MAX_V], flow[MAX_V][MAX_V];
    //flow[][]를 계산하고 총 유량을 반환한다
    int networkFlow(int source, int sink)
    {
        //flow를 0으로 초기화한다
        memset(flow, 0sizeof(flow));
        int totalFlow = 0;
        while(true)
        {
            //너비 우선 탐색으로 증가 경로를 찾는다
            vector<int> parent(MAX_V, -1);
            queue<int> q;
            parent[source] = source;
            q.push(source);
            while(!q.empty() && parent[sink] == -1)
            {
                int here = q.front(); q.pop();
                for(int there = 0; there < V; ++there)
                    //잔여 용량이 남아 있는 간선을 따라 탐색한다.
                    if(capacity[here][there] - flow[here][there] > 0 && parent[there] == -1)
                    {
                        q.push(there);
                        parent[there] = here;
                    }
            }
            //증가 경로가 없으면 종료한다
            if(parent[sink] == -1break;
            //증가 경로를 통해 유량을 얼마나 보낼지 결정한다
            int amount = INF;
            for(int p = sink; p != source; p = parent[p])
                amount = min(capacity[parent[p]][p] - flow[parent[p]][p], amount);
            //증가 경로를 통해 유량을 보낸다
            for(int p = sink; p != source; p = parent[p])
            {
                flow[parent[p]][p] += amount;
                flow[p][parent[p]] -= amount;
            }
            totalFlow += amount;
        }
        return totalFlow;
    }
    cs

     

     

     

     

     

    Ford-Fulkerson algorithm

    네트워크 유량 알고리즘

    증가 경로가 더이상 존재하지 않을 때까지 증가 경로를 찾고, 보낼 수 있는 최대 유량을 해당 경로를 따라 보내는 작업을 반복합니다.

    증가경로는 잔여 용량이 남은 간선들만을 이용하는 BFS를 이옹해 찾습니다.

    SOURCE -> SINK 의 경로를 찾았다면, 각 간선을 검사하면서 그중 최소 잔여 용량을 찾습니다. 이것이 이 경로를 따라 보낼 수 있는 최대 유량입니다.

    그 후에는 각 간선의 유량을 갱신하는데, 유량의 대칭성을 유지하기 위해 한 방향의 유량을 늘리면 다른 방향의 유량은 줄여줍니다!

     

     

     

     

     

     

    Min-cut Max-flow Theorem

    cut : source와 sink가 다른 집합에 속하도록 그래프의 정점들을 두 개의 집합으로 나눈것

     

    source가 속한 집합 : S

    sink가 속한 집합   : T

    컷 S,T의 용량      : S->T로 가는 간선들의 용량 합

    컷 S,T의 유량      : S->T로 실제로 보내는 총 유량

     

     

    속성

    1. 컷의 유량은 source->sink로 가는 총 유량과 같다

    2. 컷의 유량은 용량과 같거나 더 작다

     

     

    네트워크에 용량과 유량이 같은 컷 S`, T`가 존재하면, S`, T`는 항상 최소 컷이며, 현재 소스에서 싱크로 보내는 유량은 네트워크의 최대 유량입니다.

     

     

     

     

     

     

    인접 리스트로 Ford-Fulkerson algorithm 구현하기
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    //인접 리스트로 포드-폴커슨 알고리즘 구현하기
     
    //간선의 정보를 나타내는 구조체
    struct Edge
    {
        int target, capacity, flow;
        //역방향 간선의 포인터
        Edge* reverse;
        //이 간선의 잔여 용량을 계산한다
        int residualCapacity() const
        {
            return capacity - flow;
        }
        //이 간선을 따라 용량 amt를 보낸다
        void push(int amt)
        {
            flow += amt;
            reverse->flow -= amt;
        }
    };
    //유량 네트워크의 인접 리스트
    vector<Edge*> adj[MAX_V];
    //u에서 v로 가는 간선을 추가한다
    void addEdge(int u, int v, int capacity)
    {
        Edge* uv = new Edge(), *vu = new Edge();
        //u에서 v로 가는 간선을 초기화한다
        uv->target = v;
        uv->capacity = capacity;
        uv->flow = 0;
        uv->reverse = vu;
        //v에서 u로 가는 간선을 초기화한다. 이 간선의 용량은 0이다
        vu->target = u;
        vu->capacity = 0;
        vu->flow = 0;
        vu->reverse = uv;
        adj[u].push_back(uv);
        adj[v].push_back(vu);
    }
    cs

    각 단방향 간선 (u, v)마다 용량이 0인 유령간선(v, u)를 네트워크에 추가해 줘야 합니다.

    이 유령 간선은 유량을 상쇄하는 데만 사용합니다.

    각 간선의 유령간선에 빠르게 접근하기 위해 서로를 가르키는 포인터를 가지고 있습니다.

     

     

     

     

     

     

    시간복잡도

    f : 최대 유량

    O(|E|f) 와 O(|V||E|^2)중 작은것

    'Algorithm > 그래프' 카테고리의 다른 글

    Dinic's Algorithm  (0) 2020.02.24
    이분 매칭 문제를 해결하는 증가 경로 알고리즘  (0) 2020.02.23
    Prim's MST algorithm  (0) 2020.01.31
    Kruskal's MST algorithm  (0) 2020.01.30
    Floyd-Warshall algorithm  (0) 2020.01.23

    댓글

Designed by Tistory.