우노
[Shortest Path] 이코테 “정확한 순위” Python 풀이 본문
문제
선생님은 시험을 본 학생 N명의 성적을 분실하고, 성적을 비교한 결과의 일부만 가지고 있습니다.
학생 N명의 성적은 모두 다른데, 다음은 6명의 학생에 대하여 6번만 성적을 비교한 결과입니다.
- 1번 학생의 성적 < 5번 학생의 성적
- 3번 학생의 성적 < 4번 학생의 성적
- 4번 학생의 성적 < 2번 학생의 성적
- 4번 학생의 성적 < 6번 학생의 성적
- 5번 학생의 성적 < 2번 학생의 성적
- 5번 학생의 성적 < 4번 학생의 성적
A번 학생의 성적이 B번 학생보다 낮다면 화살표가 A에서 B를 가리키도록 할 때 위의 성적 결과를 다음 그림처럼 표현할 수 있습니다.
이 그림으로 유추해서 순위를 정확히 알 수 있는 학생도 있고, 알 수 없는 학생도 있습니다.
예를 들어 1번 학생은 5번 학생보다 성적이 낮고, 5번 학생은 4번 학생보다 성적이 낮으므로 1번 학생은 4번 학생보다 성적이 낮습니다.
따라서 1번, 3번, 5번 학생은 모두 4번 학생보다 성적이 낮다고 볼 수 있습니다.
그리고 4번 학생은 2번 학생과 6번 학생보다 성적이 낮습니다.
정리하면 4번 학생보다 성적이 낮은 학생은 3명이고, 성적이 높은 학생은 2명이므로 4번 학생의 성적 순위를 정확히 알 수 있습니다.
하지만 예시에서 4번 학생을 제외한 다른 학생은 정확한 순위를 알 수 없습니다.
학생들의 성적을 비교한 결과가 주어질 때, 성적 순위를 정확히 알 수 있는 학생은 모두 몇 명인지 계산하는 프로그램을 작성하세요.
입력 조건
- 첫째 줄에 학생들의 수 N(2 <= n <= 500)과 두 학생의 성적을 비교한 횟수 M(2 <= M <= 10,000)이 주어집니다.
- 다음 M개의 각 줄에는 두 학생의 성적을 비교한 결과를 나타내는 두 양의 정수 A와 B가 주어집니다.
- 이는 A번 학생의 성적이 B번 학생보다 낮다는 것을 의미합니다.
출력 조건
- 첫째 줄에 성적 순위를 정확히 알 수 있는 학생이 몇 명인지 출력합니다.
입력 예시
6 6
1 5
3 4
4 2
4 6
5 2
5 4
출력 예시
1
풀이
- A번 학생과 B번 학생의 성적을 비교할 때, ‘경로’를 이용하여 성적 비교 결과를 알 수 있다.
- A에서 B로 도달이 가능하다는 것은, A가 B보다 성적이 낮다는 의미가 된다.
- 따라서 A에서 B로 도달이 가능하거나, B에서 A로도 도달이 가능하다면 ‘성적 비교’가 가능한 것이다.
- 반대로 A에서 B로 도달이 불가능하거나, B에서 A로도 도달이 불가능하다면, ‘성적 비교 결과를 알 수 없는’ 경우가 되는 것이다.
- ‘성적 비교 결과를 아는 것’과 ‘성적 순위를 정확히 아는 것’은 다르다.
- ‘성적 순위를 정확히 아는 것’은 이후에 설명된다.
- 이 문제에서는 학생의 수 N이 500 이하의 정수이므로, O(N^3)의 시간 복잡도로 동작하는 플로이드 워셜 알고리즘을 이용해 문제를 해결할 수 있다.
- 따라서, 플로이드 워셜 알고리즘을 수행한 뒤에, 모든 노드에 대하여 다른 노드와 서로 도달이 가능한지를 체크하여 문제를 해결할 수 있다.
- 즉, 특정 학생이 다른 학생보다 성적이 낮거나, 높을 경우를 모두 카운팅함으로써,
- 해당 학생보다 성적이 낮고 높은 학생들의 합이, 본인을 포함해 n과 같다면,
- 해당 학생의 정확한 순위를 알 수 있다는 의미이다.
예제 코드
import sys
INF = int(1e9) # 무한을 의미하는 값으로 10억을 설정
# 노드의 개수, 간선의 개수를 입력받기
n, m = map(int, sys.stdin.readline().split())
# 2차원 리스트(그래프 표현)를 만들고, 모든 값을 무한으로 초기화
graph = [[INF] * (n + 1) for _ in range(n + 1)]
# 자기 자신에서 자기 자신으로 가는 비용은 0으로 초기화
for a in range(1, n + 1):
for b in range(1, n + 1):
if a == b:
graph[a][b] = 0
# 각 간선에 대한 정보를 입력 받아, 그 값으로 초기화
for _ in range(m):
# A에서 B로 가는 비용을 1로 설정
a, b = map(int, sys.stdin.readline().split())
graph[a][b] = 1
# 점화식에 따라 플로이드 워셜 알고리즘을 수행
for k in range(1, n + 1):
for a in range(1, n + 1):
for b in range(1, n + 1):
graph[a][b] = min(graph[a][b], graph[a][k] + graph[k][b])
# 성적 순위를 정확히 알 수 있는 학생
result = 0
# 각 학생을 번호에 따라 한 명씩 확인하며 도달 가능한지 체크
for i in range(1, n + 1):
count = 0
for j in range(1, n + 1):
# 해당 학생이 다른 학생보다 성적이 낮거나, 높을 경우를 모두 카운팅
if graph[i][j] != INF or graph[j][i] != INF:
count += 1
# 해당 학생보다 성적이 낮거나 높은 학생들의 합이, 본인을 포함해 n과 같다면,
# 해당 학생의 정확한 순위를 알 수 있다.
if count == n:
result += 1
print(result)
참고
- 이것이 취업을 위한 코딩 테스트다. with python
- https://unie2.tistory.com/729
'Algorithm > Shortest Path' 카테고리의 다른 글
[Shortest Path] 이코테 “숨바꼭질” Python 풀이 (0) | 2022.09.28 |
---|---|
[Shortest Path] 이코테 “화성 탐사” Python 풀이 (0) | 2022.09.28 |
[Shortest Path] 이코테 “플로이드” Python 풀이 (0) | 2022.09.27 |
[Shortest Path] 이코테 “전보” Python 풀이 (0) | 2022.07.04 |
[Shortest Path] 이코테 “미래 도시” Python 풀이 (0) | 2022.07.04 |
Comments