Search

[Baekjoon] 4195 친구 네트워크

Tags
Union-Find
Date
2023/06/26

설명

민혁이는 소셜 네트워크 사이트에서 친구를 만드는 것을 좋아하는 친구이다. 우표를 모으는 취미가 있듯이, 민혁이는 소셜 네트워크 사이트에서 친구를 모으는 것이 취미이다.
어떤 사이트의 친구 관계가 생긴 순서대로 주어졌을 때, 두 사람의 친구 네트워크에 몇 명이 있는지 구하는 프로그램을 작성하시오.
친구 네트워크란 친구 관계만으로 이동할 수 있는 사이를 말한다.

입력

첫째 줄에 테스트 케이스의 개수가 주어진다. 각 테스트 케이스의 첫째 줄에는 친구 관계의 수 F가 주어지며, 이 값은 100,000을 넘지 않는다. 다음 F개의 줄에는 친구 관계가 생긴 순서대로 주어진다. 친구 관계는 두 사용자의 아이디로 이루어져 있으며, 알파벳 대문자 또는 소문자로만 이루어진 길이 20 이하의 문자열이다.

출력

친구 관계가 생길 때마다, 두 사람의 친구 네트워크에 몇 명이 있는지 구하는 프로그램을 작성하시오.

예시 입력

예시 출력

2 3 Fred Barney Barney Betty Btty Wilma 3 Fred Barney Betty Wilma Barney Betty
JavaScript
복사
2 3 4 2 2 4
JavaScript
복사

풀이 과정

처음에 접근했던 방법
ArrayList를 사용해서 입력받은 이름이 있는지 없는지 확인한 후에 저장하면 되는거 아닌가 라고 생각해 다음과 같은 코드를 작성하였습니다.

실패 코드

package baekjoon.data_structure; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.LinkedList; public class _4195 { static ArrayList<LinkedList<String>> list; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringBuilder sb = new StringBuilder(); // TestCase의 수 int N = Integer.parseInt(br.readLine()); for (int i = 0; i < N; i++) { // 입력받을 친구 관계의 수 int M = Integer.parseInt(br.readLine()); list = new ArrayList<>(); for (int j = 0; j < M; j++) { String[] s = br.readLine().split(" "); // Initialization if (list.isEmpty()) { list.add(new LinkedList<>()); list.get(0).add(s[0]); list.get(0).add(s[1]); sb.append(list.get(0).size() + "\n"); continue; } int isA = -1; int isB = -1; for (int k = 0; k < list.size(); k++) { if (list.get(k).contains(s[0])) { isA = k; } else if (list.get(k).contains(s[1])) { isB = k; } } if (isA == -1 && isB == -1) { list.add(new LinkedList<>()); list.get(list.size() - 1).add(s[0]); list.get(list.size() - 1).add(s[1]); sb.append(list.get(list.size() - 1).size() + "\n"); } else if (isA == -1 && isB != -1) { list.get(isB).add(s[0]); sb.append(list.get(isB).size() + "\n"); } else if (isA != -1 && isB == -1) { list.get(isA).add(s[1]); sb.append(list.get(isA).size() + "\n"); } else if (isA != -1 && isB != -1) { for (int k = 0; k < list.get(isB).size(); k++) { list.get(isA).add(list.get(isB).get(k)); } list.remove(isB); sb.append(list.get(isA).size() + "\n"); } } } System.out.println(sb); } }
JavaScript
복사
하지만 위 코드는 시간 초과를 불러 일으켰습니다.
그래서 두번째로 유니온 파인드를 사용해보았습니다.
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; public class _4195 { // 1 static Map<String, String> parent = new HashMap<>(); static Map<String, Integer> count = new HashMap<>(); public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); StringBuilder sb = new StringBuilder(); int T = Integer.parseInt(br.readLine()); for (int t = 0; t < T; t++) { // 2 parent.clear(); count.clear(); int F = Integer.parseInt(br.readLine()); for (int i = 0; i < F; i++) { String[] friends = br.readLine().split(" "); // Initialization if (!parent.containsKey(friends[0])) { parent.put(friends[0], friends[0]); count.put(friends[0], 1); } if (!parent.containsKey(friends[1])) { parent.put(friends[1], friends[1]); count.put(friends[1], 1); } // 3 union(friends[0], friends[1]); sb.append(count.get(find(friends[0]))).append('\n'); } } System.out.print(sb.toString()); } public static String find(String x) { if (x.equals(parent.get(x))) { return x; } String p = find(parent.get(x)); parent.put(x, p); return p; } public static void union(String x, String y) { x = find(x); y = find(y); // 순서가 상관 없다 if (!x.equals(y)) { parent.put(y, x); count.put(x, count.get(x) + count.get(y)); } } }
Java
복사
흐름도 (좌: Parent, 우: Count)
A B
A
B
A
B
A
A
2
1
B C
A
B
C
A
B
C
A
A
A
3
1
1

문제가 어려운 이유

생소한 접근
1.
기존의 parent, union은 모두 Integer를 사용했었습니다.
2.
이번 문제는 String을 사용해 접근해야 합니다.
int [] parent = new int [N]; for(int i = 0; i<N; i++){ parent[i] = i+1; } public static int find(int x) { if (x == parent[x]) return x; return parent[x] = find(parent[x]); } public static void union(int x, int y) { x = find(x); y = find(y); if (truth[x]) parent[y] = x; else parent[x] = y; }
Java
복사
Map<String, String> parent 의 이유
1.
통상적인 Parent 배열 → 자기 자신으로 초기화
int [] parent = new int [N]; for(int i = 0; i<N; i++){ parent[i] = i+1; }
Java
복사
단, 친구 관계는 계속해서 증가할 수 있어 가변적인 자료구조를 사용