PS/Network Flow

백준 2316번: 도시 왕복하기 2 (Java)

닻과매 2022. 7. 5. 20:44

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

 

2316번: 도시 왕복하기 2

N개의 도시가 P개의 양방향 길로 연결되어 있다. 이석원은 1번 도시와 2번 도시 사이를 오가며 워해머를 한다. 성실한 이석원은 두 도시 사이를 최대한 많이 왔다 갔다 하려 하는데, 이때 한 번 방

www.acmicpc.net

 

 

 

 

 

 

 

 


 

풀이

라이님 블로그를 참고했습니다.

점을 한 번만 표현하기 위해, '정점 분할'을 해줍니다: 점 U를 점 U, U'으로 나누어, 점 U와 U' 사이 유량이 1인 단방향 간선으로 연결합니다.

점 U에서 점 V로 가는 양방향 간선을 다음과 같이 표현합니다: U'->V 단방향 간선, V'->U 단방향 간선

이후 에드몬드-카프 알고리즘을 수행하면 됩니다.

코드

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
import java.io.*;
import java.util.*;
 
public class Main {
 
    static int N;
    static List<List<Integer>> graph;
    static int[][] capacity, flow;
    static int[] parent;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        int P = Integer.parseInt(st.nextToken());
        capacity = new int[2*N+1][2*N+1];
        flow = new int[2*N+1][2*N+1];
        graph = new ArrayList<>();
        for (int i = 0; i <= 2*N; i++) {
            graph.add(new ArrayList<Integer>());
        }
        // i번째 점: 2*i-1, 2*i에 대응 
        for (int i = 0; i < P; i++) {
            st = new StringTokenizer(br.readLine());
            int from = 2*Integer.parseInt(st.nextToken())-1;
            int to = 2*Integer.parseInt(st.nextToken())-1;
            graph.get(from).add(from+1);
            graph.get(from+1).add(from);
            graph.get(from+1).add(to);
            graph.get(to).add(from+1);
            graph.get(to).add(to+1);
            graph.get(to+1).add(to);
            graph.get(to+1).add(from);
            graph.get(from).add(to+1);
            capacity[from][from+1= 1;
            capacity[from+1][to]++;
            capacity[to][to+1= 1;
            capacity[to+1][from]++;
        }
        // 1, 2번 점은 두 번 이상 방문 
        System.out.println(maximumFlow(23));
    }
 
    static int maximumFlow(int source, int sink) {
        int maxFlow = 0;
        while (true) {
            parent = new int[2*N+1];
            parent[source] = source;
            Queue<Integer> queue = new ArrayDeque<>();
            queue.offer(source);
            while (!queue.isEmpty() && parent[sink] == 0) {
                int cur = queue.poll();
                for (int nxt: graph.get(cur)) {
                    if (parent[nxt] == 0 && capacity[cur][nxt] - flow[cur][nxt] > 0) {
                        parent[nxt] = cur;
                        queue.offer(nxt);
                    }
                }
            }
            
            if (parent[sink] == 0break;
            
            int tempFlow = Integer.MAX_VALUE;
            for (int cur = sink; cur != source; cur = parent[cur]) {
                tempFlow = Math.min(tempFlow, capacity[parent[cur]][cur] - flow[parent[cur]][cur]);
            }
            for (int cur = sink; cur != source; cur = parent[cur]) {
                flow[parent[cur]][cur] += tempFlow;
                flow[cur][parent[cur]] -= tempFlow;
            }
            maxFlow += tempFlow;
        }
        return maxFlow;
    }
}
 
cs