※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※

 

이번에 볼 문제는 백준 18134번 문제인 치삼이의 대모험이다.
문제는 아래 링크를 확인하자.

https://www.acmicpc.net/problem/18134 

 

18134번: 치삼이의 대모험

첫 번째 줄에 골목길의 교차점 개수 N(3 ≤ N ≤ 1,000)과 골목길의 개수 M(3 ≤ M ≤ 10,000)이 주어진다. 두 번째 줄부터 M개의 줄에 골목길의 정보가 주어진다. 각 줄에는 3개의 정수로 골목길의

www.acmicpc.net

주어진 문제의 답이 되는 경로를 찾는 것은 H에서 T로 가는, vertex-disjoint하고 가중치의 총합이 최소인 두 경로의 그 가중치의 총합을 구하는 문제로 생각할 수 있다.

 

이는 주어진 그래프에서 각 에지와 꼭짓점(H와 T 제외)에 허용된 유량을 1, 각 에지의 비용을 L이라 할 때 H에서 T로 2의 유량을 최소비용으로 흘리는 문제로 생각할 수 있다. MCMF 문제를 해결하는 알고리즘을 이용해 문제를 해결해주자.

 

아래는 제출한 소스코드이다.

#define NODE 2002
#define INF 1000000007
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

int source = 0, sink = 2001;
int edge[NODE][NODE], cost[NODE][NODE];
vector<int> G[NODE];

int par[NODE];
int stepcost[NODE];
int inque[NODE];

pair<int, int> MCMF() { // {maxflow, mincost}
    int retflow = 0, retcost = 0;
    while (1) {
        memset(par, -1, sizeof(par));
        memset(inque, 0, sizeof(inque));
        fill(stepcost, stepcost + NODE, INF);
        stepcost[source] = 0;

        queue<int> que;
        que.push(source);
        inque[source] = 1;

        while (!que.empty()) {
            int cur = que.front(); que.pop();
            inque[cur] = 0;
            for (auto& nxt : G[cur]) {
                if (edge[cur][nxt] > 0 && stepcost[cur] + cost[cur][nxt] < stepcost[nxt]) {
                    stepcost[nxt] = stepcost[cur] + cost[cur][nxt];
                    par[nxt] = cur;
                    if (!inque[nxt]) {
                        que.push(nxt);
                        inque[nxt] = 1;
                    }
                }
            }
        }

        if (par[sink] == -1) break;

        int flow = INF;
        for (int i = sink; i != source; i = par[i]) flow = min(flow, edge[par[i]][i]);
        for (int i = sink; i != source; i = par[i]) {
            retcost += cost[par[i]][i] * flow;
            edge[par[i]][i] -= flow;
            edge[i][par[i]] += flow;
        }
        retflow += flow;
    }

    return make_pair(retflow, retcost);
}

int N, M, H, T;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M;
    for (int n = 1; n <= N; n++) {
        G[n].emplace_back(n + 1000);
        G[n + 1000].emplace_back(n);
        edge[n][n + 1000] = 1;
    }
    while (M--) {
        int L, U, V; cin >> L >> U >> V;
        G[U + 1000].emplace_back(V);
        G[V].emplace_back(U + 1000);
        G[V + 1000].emplace_back(U);
        G[U].emplace_back(V + 1000);
        edge[U + 1000][V] = edge[V + 1000][U] = 1;
        cost[U + 1000][V] = cost[V + 1000][U] = L, cost[U][V + 1000] = cost[V][U + 1000] = -L;
    }
    cin >> H >> T;
    G[source].emplace_back(H + 1000);
    G[T].emplace_back(sink);
    edge[source][H + 1000] = edge[T][sink] = 2;

    auto p = MCMF();
    if (p.first < 2) cout << -1;
    else cout << p.second;
}
728x90

'BOJ' 카테고리의 다른 글

[BOJ 18132 // C++] 내 이진트리를 돌려줘!!!  (0) 2023.08.13
[BOJ 18135 // C++] 겨울나기  (0) 2023.08.12
[BOJ 1925 // C++] 삼각형  (0) 2023.08.10
[BOJ 1972 // C++] 놀라운 문자열  (0) 2023.08.09
[BOJ 1996 // C++] 지뢰 찾기  (0) 2023.08.08

+ Recent posts