문제 링크
https://www.acmicpc.net/problem/5021
문제
유토피아의 왕이 사망했다. 왕은 자손을 남기지 않고 사망했기 때문에, 왕위를 계승할 사람을 지목하지 않았다. 왕실 귀족은 왕위를 주장하기 시작했다. 유토피아의 법에는 왕의 계승자가 없는 경우에, 나라를 세운 사람과 혈통이 가까운 사람이 유토피아를 통치한다는 조항이 있다.
나라를 세운 사람과 혈통이 가장 가까운 사람은 그의 자손이 아닌 사람과 피가 덜 섞인 사람이다. 모든 사람은 아버지의 혈통과 어머니의 혈통을 반 씩 받게 된다. 나라를 세운 사람의 자식은 1/2 왕족이며, 그 아들이 왕족이 아닌 사람과 결혼한 경우에는 아들의 자식은 1/4 왕족이 된다.
가장 나라를 세운 사람과 혈통이 가까운 사람을 찾는 프로그램을 작성하시오.
입력
첫째 줄에 N과 M이 주어진다. (2 ≤ N, M ≤ 50)
둘째 줄에 유토피아를 세운 사람의 이름이 주어진다.
다음 N개 줄에는 가족 정보가 주어진다. 정보는 이름 세 개로 이루어져 있고, 공백으로 구분되어져 있다. 첫 번째 이름은 자식의 이름이고, 뒤의 두 이름은 부모의 이름이다.
다음 M개 줄에는 왕위를 계승받기를 주장하는 사람의 이름이 한 줄에 하나씩 주어진다.
모든 이름은 1~10글자이며, 알파벳 소문자로만 이루어져 있다. 나라를 세운 사람이 왕위를 계승하는 경우나, 누군가의 자식인 경우는 없다.
출력
첫째 줄에 유토피아를 세운 사람과 가장 혈통이 가까운 사람의 이름을 출력한다. 항상 답이 유일한 경우만 입력으로 주어진다.
문제에 주어지는 가족 관계는 성별, 나이를 고려하지 않고 만들었기 때문에, 실제로는 말이 안되는 경우가 나올 수도 있다. 하지만, 모든 자식의 부모는 유일하며, 다시 자식이 부모의 부모가 되는 경우도 없다. 또, 한 사람이 여러 명의 자식이 될 수도 없다.
예제 입력 1
9 2
edwardi
charlesi edwardi diana
philip charlesi mistress
wilhelm mary philip
matthew wilhelm helen
edwardii charlesi laura
alice laura charlesi
helen alice bernard
henrii edwardii roxane
charlesii elizabeth henrii
charlesii
matthew
예제 출력 1
matthew
알고리즘 분류
- 위상 정렬
풀이
위상 정렬보다는 해싱을 사용하는 것이 좀 어려웠다.
map을 2개를 사용하는데, 하나는 각 사람마다 자식들을 저장하기 위해 필요하며, 또 하나는 위상 정렬에 필요한 차수와 혈통을 나타내는 double형을 저장하기 위해 필요하다.
N개의 가족 관계를 입력받으면서 부모 자식 관계를 저장하고 차수를 저장하는데, 부모는 무조건 2명이기 때문에 자식의 차수는 2이다.
또한, 유토피아를 세운 사람은 반드시 차수가 0이 되고, 차수가 0인 사람들이 먼저 큐에 추가된다.
해싱을 마무리했으면 이제부터는 위상 정렬로 혈통을 정리한다.
큐에 추가된, 차수가 0인 사람들을 큐에서 pop하면서 자식들의 차수를 1씩 제거하고 혈통을 더해준다.
차수가 0인 자식들은 큐에 추가하며, 이 때 왕족의 자식은 왕족 혈통의 1/2이기 때문에 혈통을 절반으로 나눈다.
이렇게 해서 모든 사람들의 혈통이 map에 기록되게 된다.
M명의 사람들 중 혈통이 가장 높은 사람이 유토피아를 세운 사람과 가장 혈통이 가까운 사람이 된다.
코드
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <queue>
#include <algorithm>
#define FASTIO cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
using namespace std;
int N, M;
string Root, A, B, C;
unordered_map<string, vector<string> > Childs;
unordered_map<string, pair<int, double> > Degrees;
vector<string> Query;
double MaxDegree = -1.0;
string Answer;
void input() {
cin >> N >> M;
Query.resize(M);
cin >> Root;
Degrees[Root] = make_pair(0, 1.0);
for (int i = 0; i < N; i++) {
cin >> A >> B >> C;
if (Degrees.find(B) == Degrees.end()) {
Degrees.insert(make_pair(B, make_pair(0, 0)));
}
if (Degrees.find(C) == Degrees.end()) {
Degrees.insert(make_pair(C, make_pair(0, 0)));
}
Degrees[A] = make_pair(2, 0);
if (Childs.find(B) == Childs.end()) {
vector<string> Vec;
Vec.push_back(A);
Childs.insert(make_pair(B, Vec));
}
else {
Childs[B].push_back(A);
}
if (Childs.find(C) == Childs.end()) {
vector<string> Vec;
Vec.push_back(A);
Childs.insert(make_pair(C, Vec));
}
else {
Childs[C].push_back(A);
}
}
for (int i = 0; i < M; i++) {
cin >> Query[i];
}
}
void settings() {
queue<string> Q;
for (auto IT : Degrees) {
int Degree = IT.second.first;
if (Degree == 0) {
Q.push(IT.first);
}
}
while (!Q.empty()) {
string Parent = Q.front();
Q.pop();
for (int i = 0; i < (int)Childs[Parent].size(); i++) {
string Child = Childs[Parent][i];
Degrees[Child].second += Degrees[Parent].second;
Degrees[Child].first--;
if (Degrees[Child].first == 0) {
Q.push(Child);
Degrees[Child].second /= 2;
}
}
};
for (int i = 0; i < M; i++) {
string Now = Query[i];
double Degree = Degrees[Now].second;
if (MaxDegree < Degree) {
MaxDegree = Degree;
Answer = Now;
}
}
}
void printAnswer() {
cout << Answer << "\n";
}
int main() {
FASTIO
input();
settings();
printAnswer();
return 0;
}
'BOJ > Gold' 카테고리의 다른 글
[BOJ/Gold 4] 백준 21939 문제 추천 시스템 Version 1(C++) (0) | 2024.12.29 |
---|---|
[BOJ/Gold 4] 백준 5594 最悪の記者(C++) (0) | 2024.12.28 |
[BOJ/Gold 5] 백준 31423 신촌 통폐합 계획(C++) (0) | 2024.12.27 |
[BOJ/Gold 2] 백준 32360 더워!(C++) (0) | 2024.12.26 |
[BOJ/Gold 4] 백준 32197 절연 구간 최소화(C++) (4) | 2024.12.25 |