2 분 소요

1. 문제

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

  • 해시, 집합, 그래프 문제
// 문제
민혁이는 소셜 네트워크 사이트에서 친구를 만드는 것을 좋아하는 친구이다.
우표를 모으는 취미가 있듯이,
민혁이는 소셜 네트워크 사이트에서 친구를 모으는 것이 취미이다.

어떤 사이트의 친구 관계가 생긴 순서대로 주어졌을 때,
두 사람의 친구 네트워크에 몇 명이 있는지 구하는 프로그램을 작성하시오.

친구 네트워크란 친구 관계만으로 이동할 수 있는 사이를 말한다.

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

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

// 예제 입력 1
2
3
Fred Barney
Barney Betty
Betty Wilma
3
Fred Barney
Betty Wilma
Barney Betty

// 예제 출력 1
2
3
4
2
2
4


2. 핵심 아이디어

  • 해시를 활용한 Union-Find 알고리즘을 이용해 문제를 풀 수 있음
  • Python에서는 dictionary를 해시처럼 사용할 수 있음
  • Union-Find 알고리즘
    • 원소들의 연결 여부를 확인하는 알고리즘
    • 더 작은 원소를 부모로 삼도록 설정
def find(x) :
  if x == parent[x] :
    return x
  else :
    p = find(parent[x])
    parent[x] = p
    return parent[x]

def union(x, y) :
  x = find(x)
  y = find(y)

  parent[y] = x

parent = []

for i in range(0, 5) :
  parent.append(i)

union(1, 4)
union(2, 4)

for i in range(1, len(parent)) :
  print(find(i), end = ' ')


3. Python 문제풀이

import sys

def find(x) :
  if x == parent[x] :
    return x
  else :
    p = find(parent[x])
    parent[x] = p
    return parent[x]

def union(x, y) :
  x = find(x)
  y = find(y)

  if x != y :
    parent[y] = x
    number[x] += number[y]

test_case = int(sys.stdin.readline())

for _ in range(test_case) :
  parent = dict()
  number = dict()

  f = int(sys.stdin.readline())

  for _ in range(f) :
    x, y = sys.stdin.readline().rstrip().split(' ')

    if x not in parent :
      parent[x] = x
      number[x] = 1
    if y not in parent :
      parent[y] = y
      number[y] = 1

    union(x, y)
    print(number[find(x)])


4. Java 문제풀이

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

public class Main {
  static int[] parent;
  static int[] number;

  public static void main(String[] args) throws NumberFormatException, IOException {
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    StringTokenizer st;

    int test_case = Integer.parseInt(br.readLine());

    StringBuilder sb = new StringBuilder();
    while (test_case-- > 0) {
      int F = Integer.parseInt(br.readLine());

      parent = new int[F * 2];
      number = new int[F * 2];
      for (int i = 0; i < F * 2; i++) {
        parent[i] = i;
        number[i] = 1;
      }

      int idx = 0;
      Map<String, Integer> map = new HashMap<>();

      for (int i = 0; i < F; i++) {
        st = new StringTokenizer(br.readLine());
        String a = st.nextToken();
        String b = st.nextToken();

        if (!map.containsKey(a)) {
            map.put(a, idx++);
        }
        if (!map.containsKey(b)) {
            map.put(b, idx++);
        }
        sb.append(union(map.get(a), map.get(b)) + "\n");
      }
    }

    bw.write(sb.toString());
    bw.flush();
    bw.close();
    br.close();
  }

  public static int find(int x) {
    if (x == parent[x]) {
      return x;
    }
    return parent[x] = find(parent[x]);
  }

  public static int union(int x, int y) {
    x = find(x);
    y = find(y);

    // 항상 x < y인 값이 들어온다고 가정
    if (x != y) {
      parent[y] = x;
      number[x] += number[y]; // y에 있던 층의 개수를 더해 줌.
    }
    return number[x];
  }
}

댓글남기기