같은 중간지점을 이용하지 않고 출발지 1에서 목적지 v까지 배 두대를 이용해서 움직일 때 소모값의 최소값을 구하는 문제다.


처음 풀었던 왕복여행 문제와 비슷하긴 하나 같은 중간지점을 이용하지 않는다는 점이 중요하다.


간선을 가지고 특정 중간지점을 두번 사용했는지 확인하기 위해 정점을 나눈다.



예제를 가지고 문제를 푼다고 하면 그림과 같이 1~n번 정점을 두개로 나누고, 출발지, 도착지를 제외한 나머지 정점의 내부 간선의 cap을 1로 둔다.


이렇게 하면 각 정점을 한번밖에 이용하지 못하게 된다. 출발지, 도착지의 내부간선의 cap은 2다.


정점을 쪼갤 때 번호지정은 편한대로 하면 된다.


<코드>

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
 
typedef pair<intint> pii;
 
struct E {
    int t, c, co;
    E *rev;
    E(int t, int c, int co) : t(t), c(c), co(co) {}
};
 
void aE(int u, int v, int c, int co, vector<vector<*>> &g) {
    E *ori = new E(v, c, co);
    E *rev = new E(u, 0-co);
    ori->rev = rev;
    rev->rev = ori;
    g[u].push_back(ori);
    g[v].push_back(rev);
}
 
int n, m, s, k, res, d[2010], INF = 2e9;
pii f[2010];
bool ch[2010];
 
int main() {
    while (scanf("%d%d"&n, &m) != EOF) {
        res = 0; k = 2 * n + 1;
        vector<vector<*>> g(2 * n + 2);
        aE(1220, g);
        aE(2 * n - 12 * n, 20, g);
        for (int i = 4; i < g.size() - 2; i += 2) aE(i - 1, i, 10, g);
        aE(s, 120, g);
        aE(2 * n, k, 20, g);
        for (int i = 0; i < m; i++) {
            int a, b, c;
            scanf("%d%d%d"&a, &b, &c);
            a *= 2; b *= 2;
            aE(a, b - 11, c, g);
        }
        while (1) {
            memset(f, -1sizeof(f));
            memset(ch, falsesizeof(ch));
            fill(d, d + g.size(), INF);
            queue<int> q;
            q.push(s);
            d[s] = 0;
            while (q.size()) {
                int x = q.front();
                q.pop();
                ch[x] = 0;
                for (int i = 0; i < g[x].size(); i++) {
                    auto nx = g[x][i];
                    if (nx->> 0 && d[nx->t] > d[x] + nx->co) {
                        d[nx->t] = d[x] + nx->co;
                        f[nx->t] = { x,i };
                        if (!ch[nx->t]) {
                            ch[nx->t] = 1;
                            q.push(nx->t);
                        }
                    }
                }
            }
            if (f[k].first == -1break;
            for (int x = k; x != s; x = f[x].first) {
                res += g[f[x].first][f[x].second]->co;
                g[f[x].first][f[x].second]->-= 1;
                g[f[x].first][f[x].second]->rev->+= 1;
            }
        }
        printf("%d\n", res);
    }
    return 0;
}
 
cs


'BOJ' 카테고리의 다른 글

13200 light up  (0) 2017.09.12
3187 양치기 꿍  (0) 2017.09.12
3056 007  (0) 2017.09.06
1733 등번호  (0) 2017.09.06
2311 왕복 여행  (0) 2017.09.06

+ Recent posts