www.acmicpc.net/problem/4195

 

4195번: 친구 네트워크

첫째 줄에 테스트 케이스의 개수가 주어진다. 각 테스트 케이스의 첫째 줄에는 친구 관계의 수 F가 주어지며, 이 값은 100,000을 넘지 않는다. 다음 F개의 줄에는 친구 관계가 생긴 순서대로 주어진

www.acmicpc.net

 

친구의 관계가 주어진다. 예제를 보면

 

Fred Barney

Betty Wilma

Barney Betty

 

가 주어지는데 

 

Fred - Barney 가 연결되었으니 총 2명

Betty - Wilma 가 연결되었으니 총 2명

Barney - Betty 인데 Betty - Wilma, Barney - Fred 가 서로 친구이니 총 4명

 

즉, 집합이 주어지는데 같은 부모 노드 같은 구성원이 존재한다면 Union 시켜주면 된다.

다만 find 연산과 union 연산을 살짝 변형해줬는데 그냥 map을 쓰면 시간 초과가 난다.

따라서 unordered_map을 사용하면 O(1)에 처리할 수 있다.

 

string find(string x) {
	if (!m.count(x)) {
		m[x] = { x,1 };
	}
	if (m[x].first == x) return x;
	return m[x].first = find(m[x].first);
}

 

m.count(x) 로 x가 map에 존재하지 않는다면 크기 1로 생성해준다.

 

int merge(string a, string b) {
	a = find(a);
	b = find(b);

	if (a == b) return m[a].second;
	if (m[a].second < m[b].second) swap(a, b);
	m[a].second += m[b].second;
	m[b].first = a;
	return m[a].second;
}

 

병합하는 부분을 살펴보면 m[a].second와 m[b].second 를 비교해서 더 큰 집합에 작은 집합을 속하게 해 준다.

여기까지 이해했다면 입력받고 출력하는 건 쉽다.

 

#include <bits/stdc++.h>
using namespace std;

int tc, n;
unordered_map<string, pair<string, int>> m;

string find(string x) {
	if (!m.count(x)) {
		m[x] = { x,1 };
	}
	if (m[x].first == x) return x;
	return m[x].first = find(m[x].first);
}

int merge(string a, string b) {
	a = find(a);
	b = find(b);

	if (a == b) return m[a].second;
	if (m[a].second < m[b].second) swap(a, b);
	m[a].second += m[b].second;
	m[b].first = a;
	return m[a].second;
}

int main() {
	ios::sync_with_stdio(false); cin.tie(0);

	cin >> tc;
	while (tc--) {
		cin >> n;
		m.clear();
		for (int i = 0; i < n; i++) {
			string a, b;
			cin >> a >> b;
			cout << merge(a, b) << '\n';
		}
	}

	return 0;
}

 

'BOJ' 카테고리의 다른 글

BOJ 2293 동전 1, 2294 동전 2  (0) 2020.10.23
BOJ 1932 정수 삼각형  (0) 2020.10.22
BOJ 1976 여행 가자  (0) 2020.10.15
BOJ 2470 두 용액  (0) 2020.10.11
BOJ 7795 먹을 것인가 먹힐 것인가  (0) 2020.10.11

+ Recent posts