백준 2660번 회장 뽑기 G5
문제
월드컵 축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이 모임은 만들어진지 얼마 되지 않았기 때문에 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다. 예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다. 4점, 5점 등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다.회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.
입력
입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다.
둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터 회원의 수만큼 붙어 있다. 마지막 줄에는 -1이 두 개 들어있다.
출력
첫째 줄에는 회장 후보의 점수와 후보의 수를 출력하고, 두 번째 줄에는 회장 후보를 오름차순으로 모두 출력한다.
알고리즘 분류 보기
그래프 이론, 그래프 탐색, 너비 우선 탐색, 최단 경로, 플로이드 워셜
오늘도 플로이드 워셜 문제가 나왔다.
파이썬 및 C++로 풀이하였다.
가장 먼 친구와의 거리가 제일 작은 사람을 찾는 것으로 문제를 요약할 수 있다.
인접 행렬을 이용해서 모든 친구와의 거리를 구하는 것을 플로이드 워셜을 통해 구하면 된다.
회원의 수는 50명이기 때문에 가장 먼 친구와의 거리는 1~50이다.
마지막 출력을 위해 가장 먼 친구의 거리를 인덱스로 삼아서 자신의 번호를 담는 것으로 구현했다.
플로이드 워셜을 사용했으므로, 시간 복잡도는 O(n^3)이다.
파이썬 코드 보기
import sys
n = int(sys.stdin.readline())
dp = [[1000] * n for _ in range(n)]
for i in range(n): dp[i][i] = 0
while True:
a, b = map(int, sys.stdin.readline().split())
if a == -1 and b == -1: break
dp[a-1][b-1] = 1
dp[b-1][a-1] = 1
for k in range(n):
for i in range(n):
for j in range(n):
if i == j or dp[i][k] == 0 or dp[k][j] == 0: continue
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j])
min_v = 50
result = [[] for _ in range(50+1)]
for i in range(n):
v = max(dp[i])
if v < min_v:
min_v = v
result[v].append(i+1)
print(min_v, len(result[min_v]))
print(' '.join(map(str, result[min_v])))
C++ 코드 보기
#include <iostream>
#include <vector>
#include <algorithm>
#include <deque>
using namespace std;
int dp[51][51] = {0,};
vector<int> result[51];
int main(void)
{
int n; cin>>n;
for (int i=1; i<n+1; ++i)
{
for (int j = 1; j<n+1; ++j)
{
dp[i][j] = 50;
}
}
for (int i=1; i<n+1; ++i)
dp[i][i] = 0;
while (true)
{
int a, b; cin>>a>>b;
if (a == -1 || b == -1) break;
dp[a][b]=1;
dp[b][a]=1;
}
for (int k=1; k<n+1; ++k)
for (int i=1; i<n+1; ++i)
for (int j = 1; j<n+1; ++j)
dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
int min_v = *max_element(dp[1],dp[1]+n+1);
for (int i=1; i<n+1; ++i)
{
int v = *max_element(dp[i],dp[i]+n+1);
if (v < min_v) min_v = v;
result[v].push_back(i);
}
cout<<min_v<<" "<<result[min_v].size()<<"\n";
for (int i=0; i<result[min_v].size(); ++i)
cout<<result[min_v][i]<<" ";
}
1일 차 문제인 경로 찾기와 2일 차 문제인 케빈 베이컨의 6단계 법칙을 합친 적당한 문제였다.
'알고리즘 문제 풀이 > 항해99 코테 스터디' 카테고리의 다른 글
[99클럽/파이썬 챌린저/6일차] 키 순서 (0) | 2024.11.02 |
---|---|
[99클럽/파이썬 챌린저/5일차] 공주님의 정원 (0) | 2024.11.01 |
[99클럽/파이썬 챌린저/4일차] 웜홀 (0) | 2024.10.31 |
[99클럽/파이썬 챌린저/2일차] 케빈 베이컨의 6단계 법칙 (0) | 2024.10.29 |
[99클럽/파이썬 챌린저/1일차] 경로 찾기 (0) | 2024.10.28 |