|
| 1 | +--- |
| 2 | +title: "이분매칭(Bipartite Matching)" |
| 3 | +date: 2024-03-07 |
| 4 | +# toc: true |
| 5 | +categories: |
| 6 | + - algorithm |
| 7 | +tags: |
| 8 | + - algo |
| 9 | + - math |
| 10 | +--- |
| 11 | + |
| 12 | +두 그룹이 있을 때, 각 그룹 노드 들이 모두 서로 다른 매칭(연결)에 속하게 만들 수 있는 그래프를 이분 그래프(Bipartite Graph) 라고 한다. |
| 13 | + |
| 14 | + |
| 15 | +<br> |
| 16 | + |
| 17 | +이분 매칭은 두 그룹을 이분 그래프와 같이 매칭해나가는 알고리즘이다. |
| 18 | + |
| 19 | +<br> |
| 20 | + |
| 21 | +주로 사람에게 일을 1개씩 부여해서 최대한 모든 사람이 일할 수 있는 방법을 찾거나, 소개팅같이 1-1로 매칭할때 최대한 모든 사람이 매칭되도록 하는 등… 결론은 두 그룹으로 나눌 수 있고, 연결(매칭)을 지을 수 있다면 이분 매칭을 통해 최대한 두 그룹을 매칭시켜줄 수 있다. |
| 22 | + |
| 23 | + |
| 24 | +<br> |
| 25 | + |
| 26 | +하지만, 이 역시 그래프이기 때문에 그래프와 관련된 다양한 알고리즘이 사용될 수 있다. |
| 27 | + |
| 28 | + |
| 29 | +<br> |
| 30 | + |
| 31 | +### 이분 매칭은 어떻게 이뤄지나? |
| 32 | + |
| 33 | +이분 매칭은 몇가지 방법이 있지만, 그 중 가장 이해하기 쉬운건 DFS 를 기반으로 한다. 간단한 예시로 열형강호 문제를 기반으로 하는 경우, 현재 노드가 연결하고자 하는 다른 그룹의 노드가 이미 연결된 경우, DFS 를 통해서 기존 연결을 변경하여서 연결수를 늘릴 수 있을 지를 확인한다. 아래 그림을 확인하자. |
| 34 | + |
| 35 | +<p align="center"> |
| 36 | + <img width="600" src="/assets/images/BipartiteMatching-01.png" > |
| 37 | +</p> |
| 38 | +<p align="center"> |
| 39 | + <img width="600" src="/assets/images/BipartiteMatching-02.png" > |
| 40 | +</p> |
| 41 | +<p align="center"> |
| 42 | + <img width="600" src="/assets/images/BipartiteMatching-03.png" > |
| 43 | +</p> |
| 44 | + |
| 45 | + |
| 46 | + |
| 47 | +<br> |
| 48 | + |
| 49 | +기존 목표는 두 그룹을 최대한 많이 연결을 하는 것이다. 2번 차례가 되어 연결을 하려 할 때, 기존 1-a 의 연결을 유지하는 것보다, 1의 연결을 변경하는 것이 더 좋다는 것은 직관적으로 알 수 있다. 각 노드별로 탐색하기에 시간복잡도는 아래와 같다. |
| 50 | + |
| 51 | +<br> |
| 52 | + |
| 53 | +**시간 복잡도 : O(V*E^2)** |
| 54 | +- V : 간선(연결 수) |
| 55 | +- E : 노드의 수 (그룹 대상의 수) |
| 56 | + |
| 57 | +<br> |
| 58 | + |
| 59 | +이런 일련의 과정을 DFS와 같이 보게 된다면… 최대 연결을 지으려고 할 때, 2번 → a → 1번 에게 각각 전파하면서 다른 연결을 지을 수 있는지 탐색하게 된다. 이렇게 최대 연결을 늘리는 경로를 ‘증가 경로’라고 부른다. |
| 60 | + |
| 61 | + |
| 62 | +<br> |
| 63 | + |
| 64 | +> 어어..? 잠시만요.. 뭔가.. 떠오르는 거 같기도 한데… 혹시 포드 풀커슨?! |
| 65 | +
|
| 66 | + |
| 67 | +<br> |
| 68 | + |
| 69 | +맞다.. 위에서 말했듯이 그래프로 이뤄지기 때문에… 각 그룹에 시작점, 마지막 점을 연결하면 최대유량 문제와 동일하게 된다. 단지 각 연결의 값이 1이라는 점 빼고…! 따라서, DFS 외에 BFS 로 탐색하여 증가 경로를 찾을 수 있고, 시간복잡도를 더 줄이는 다른 방식도 있다. |
| 70 | + |
| 71 | +<br> |
| 72 | + |
| 73 | +포드 풀커슨, 에드몬트 카프.... |
| 74 | + |
| 75 | +```java |
| 76 | +// boolean[] c //매칭 여부 |
| 77 | +// ArrayList<ArrayList<Integer>> t //그래프 |
| 78 | +// int[] bb //매칭된 노드 번호 저장 배열 |
| 79 | + |
| 80 | +//매칭 성공 = true return. |
| 81 | +public static boolean dfs(int x) { |
| 82 | + for(int i=0; i<aa.get(x).size(); i++) { |
| 83 | + int t=aa.get(x).get(i); |
| 84 | + if(c[t]) {continue;} //이미 매칭된 경우 pass |
| 85 | + c[t]=true; |
| 86 | + //매칭될 것이 있는 경우 |
| 87 | + if(bb[t]==0||dfs(bb[t])) {bb[t]=x; return true;}//매칭 |
| 88 | + } |
| 89 | + return false; |
| 90 | + } |
| 91 | + |
| 92 | +// 전체 코드 |
| 93 | + |
| 94 | +public class Main { |
| 95 | + |
| 96 | + public static boolean[] c=new boolean[202]; |
| 97 | + public static ArrayList<ArrayList<Integer>> aa=new ArrayList<ArrayList<Integer>>(); |
| 98 | + public static int[] bb=new int[202]; |
| 99 | + |
| 100 | + public static boolean dfs(int x) { |
| 101 | + for(int i=0; i<aa.get(x).size(); i++) { |
| 102 | + int t=aa.get(x).get(i); |
| 103 | + if(c[t]) {continue;} |
| 104 | + c[t]=true; |
| 105 | + if(bb[t]==0||dfs(bb[t])) {bb[t]=x; return true;} |
| 106 | + } |
| 107 | + return false; |
| 108 | + } |
| 109 | + public static void main(String[] args) { |
| 110 | + Scanner sc=new Scanner(System.in); |
| 111 | + int N=sc.nextInt(); int M=sc.nextInt(); |
| 112 | + |
| 113 | + for(int i=0; i<=N ;i++) { |
| 114 | + aa.add(new ArrayList<Integer>()); |
| 115 | + } |
| 116 | + for(int i=1; i<=N; i++) { |
| 117 | + int a=sc.nextInt(); |
| 118 | + for(int j=0; j<a; j++) { |
| 119 | + int b=sc.nextInt(); |
| 120 | + aa.get(i).add(b); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + int count=0; |
| 125 | + for(int i=1; i<=N; i++) { |
| 126 | + c=new boolean[202]; |
| 127 | + if(dfs(i)) {count++;} |
| 128 | + } |
| 129 | + System.out.println(count); |
| 130 | + |
| 131 | + } |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | + |
| 136 | + |
| 137 | +**추천 문제** |
| 138 | + |
| 139 | + 문제로는 [11375: 열혈강호](https://www.acmicpc.net/problem/11375)를 추천한다. |
| 140 | + |
| 141 | +<br> |
| 142 | + |
| 143 | + |
0 commit comments