📖 백준 4195번 : https://www.acmicpc.net/problem/4195

| 시간 제한 | 메모리 제한 |
|---|---|
| 3 초 | 256 MB |
민혁이는 소셜 네트워크 사이트에서 친구를 만드는 것을 좋아하는 친구이다. 우표를 모으는 취미가 있듯이, 민혁이는 소셜 네트워크 사이트에서 친구를 모으는 것이 취미이다.
어떤 사이트의 친구 관계가 생긴 순서대로 주어졌을 때, 두 사람의 친구 네트워크에 몇 명이 있는지 구하는 프로그램을 작성하시오.
친구 네트워크란 친구 관계만으로 이동할 수 있는 사이를 말한다.
첫째 줄에 테스트 케이스의 개수가 주어진다. 각 테스트 케이스의 첫째 줄에는 친구 관계의 수 F가 주어지며, 이 값은 100,000을 넘지 않는다. 다음 F개의 줄에는 친구 관계가 생긴 순서대로 주어진다. 친구 관계는 두 사용자의 아이디로 이루어져 있으며, 알파벳 대문자 또는 소문자로만 이루어진 길이 20 이하의 문자열이다.
친구 관계가 생길 때마다, 두 사람의 친구 네트워크에 몇 명이 있는지 구하는 프로그램을 작성하시오.
입력값이 최대 100,000이 주어지기 때문에 탐색을 반복하는 방식으로는 시간 제한 안에 풀 수 없다. 따라서 Union-Find를 통해서 빠르게 집합을 만들고 각 집합의 크기를 구해내도록 했다. 입력값으로 노드가 정수로 주어지지 않고 문자열로 주어지기 때문에 map을 사용해서 각 문자열의 key값을 고유하게끔 설정했다.
map<key, value> 형태이기 때문에 map<string, int>로 친구를 고유하게 식별하고 각 친구의 노드를 정수로 설정했다. 입력을 받을 때, 문자열 값이 중복되는지 일일이 체크하는 것은 시간이 너무 오래 걸리므로 map을 활용해 중복을 방지하고 value값인 정수를 cnt++로 받았다. 따라서 최대 200,000 위치의 노드가 존재할 수 있으므로 parent배열의 크기를 200,000으로 설정했다. 입력을 받을 때마다 노드를 이어주고 집합의 크기를 출력한다. 테스트 케이스가 여러개 존재할 수 있으므로, 초기화를 반복해주면 끝이다.
#include <iostream>
#include <map>
#include <algorithm>
using namespace std;
int parent[200000];
int Find(int x) {
if (parent[x] < 0) return x;//음수 값을 가진다면 x가 루트 노드
return parent[x] = Find(parent[x]);//경로 압축
}
void Union(int x, int y) {
x = Find(x);
y = Find(y);
if (x == y) return;//이미 같은 집합이므로 무시
if (parent[x] < parent[y]) {
parent[x] += parent[y];//x의 크기 증가
parent[y] = x;//y가 x를 루트로 가리키도록 한다
}
else {
parent[y] += parent[x];//y의 크기 증가
parent[x] = y;//x가 y를 루트로 가리키도록 한다
}
}
bool isUnion(int x, int y) {
x = Find(x);
y = Find(y);
return x == y;
}
int size(int x) {
return -parent[Find(x)];
}
int main() {
ios::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
int t, n;
string a, b;
cin >> t;
for (int i = 0; i < t; i++) {
cin >> n;
//초기화
int cnt = 0;
map<string, int> friends;
fill(parent, parent + 2 * n, -1);
for (int i = 0; i < n; i++) {
cin >> a >> b;
friends.insert({ a, cnt++ });
friends.insert({ b, cnt++ });
Union(friends[a], friends[b]);
cout << size(friends[a]) << '\n';
}
}
return 0;
}