문제 출처 - Baekjoon Online Judge
문제는 여기
[문제]
모양은 같으나, 무게가 모두 다른 N개의 구슬이 있다. N은 홀수이며, 구슬에는 번호가 1,2,...,N으로 붙어 있다. 이 구슬 중에서 무게가 전체의 중간인 (무게 순서로 (N+1)/2번째) 구슬을 찾기 위해서 아래와 같은 일을 하려 한다.
우리에게 주어진 것은 양팔 저울이다. 한 쌍의 구슬을 골라서 양팔 저울의 양쪽에 하나씩 올려 보면 어느 쪽이 무거운가를 알 수 있다. 이렇게 M개의 쌍을 골라서 각각 양팔 저울에 올려서 어느 것이 무거운가를 모두 알아냈다. 이 결과를 이용하여 무게가 중간이 될 가능성이 전혀 없는 구슬들은 먼저 제외한다.
예를 들어, N=5이고, M=4 쌍의 구슬에 대해서 어느 쪽이 무거운가를 알아낸 결과가 아래에 있다.
- 구슬 2번이 구슬 1번보다 무겁다.
- 구슬 4번이 구슬 3번보다 무겁다.
- 구슬 5번이 구슬 1번보다 무겁다.
- 구슬 4번이 구슬 2번보다 무겁다.
위와 같이 네 개의 결과만을 알고 있으면, 무게가 중간인 구슬을 정확하게 찾을 수는 없지만, 1번 구슬과 4번 구슬은 무게가 중간인 구슬이 절대 될 수 없다는 것은 확실히 알 수 있다. 1번 구슬보다 무거운 것이 2, 4, 5번 구슬이고, 4번 보다 가벼운 것이 1, 2, 3번이다. 따라서 답은 2개이다.
M 개의 쌍에 대한 결과를 보고 무게가 중간인 구슬이 될 수 없는 구슬의 개수를 구하는 프로그램을 작성하시오.
[입력]
첫 줄은 구슬의 개수를 나타내는 정수 N(1 ≤ N ≤ 99)과 저울에 올려 본 쌍의 개수 M(1 ≤ M ≤ N(N-1)/2)이 주어진다. 그 다음 M 개의 줄은 각 줄마다 두 개의 구슬 번호가 주어지는데, 앞 번호의 구슬이 뒤 번호의 구슬보다 무겁다는 것을 뜻한다.
[출력]
첫 줄에 무게가 중간이 절대로 될 수 없는 구슬의 수를 출력 한다.
[풀이]
1. 값을 입력받아주고 [큰 구슬][작은 구슬]에는 1을 [작은 구슬][큰 구슬]에는 -1을 담아준다.
2. 플로이드 와샬을 사용해 출발>경유, 경유>도착의 크기가 같고 도착>시작의 크기가 0이 아닌 경우 출발>도착을 출발 >경유 값을 넣는다.
3. 플로이드 와샬을 통해 자기 자신을 기준으로 더 큰 구슬과 더 작은 구슬을 구할 수 있다.
4. 이를 사용해 큰 구슬의 개수와 작은 구슬의 개수를 구해준다.
5. 큰 구슬과 작은 구슬의 개수가 반보다 큰 경우 정답 값을 증가시켜준다.
6. 결과를 출력해준다.
[접근]
1. DFS로 문제를 해결하려고 하였다.
2. 하지만 플로이드 와샬을 사용하면 되겠다고 생각하여 플로이드 와샬을 사용해 해결하였다.
[코드]
import java.io.*;
import java.util.*;
public class Main {
static int n, m;
static int[][] arr;
static int mid, ans;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
arr = new int[n + 1][n + 1];
// 값을 입력받기
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
arr[a][b] = 1; // 큰 구슬은 1
arr[b][a] = -1; // 작은 구슬은 -1
}
for (int i = 1; i <= n; i++) { // 경유지
for (int j = 1; j <= n; j++) { // 출발지
// 자기 자신의 경우 탐색할 필요 없음
if (i == j)
continue;
for (int k = 1; k <= n; k++) { // 도착지
// 같은 경우 탐색할 필요가 없음
if (i == k || k == j)
continue;
// 출발>경유, 경유>도착의 크기가 같고 도착>시작의 크기가 0이 아닌 경우
if (arr[k][i] != 0 && arr[j][i] == arr[i][k])
arr[j][k] = arr[j][i]; // 출발>도착 = 출발 >경유
}
}
}
int[] bigger = new int[n + 1];
int[] smaller = new int[n + 1];
// 기준 구슬보다 작아야하는 갯수, 커야하는 갯수를 구하기
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
// 큰 구슬인 경우
if (arr[i][j] == 1)
bigger[i]++;
// 작은 구슬인 경우
if (arr[i][j] == -1)
smaller[i]++;
}
}
// 중간값
mid = (n / 2) + 1;
// 중간값보다 많은 경우 중간값이 될 수 없으므로 정답수 증가
for (int i = 1; i <= n; i++) {
//중간값보다 많은 경우
if (bigger[i] >= mid)
ans++;
// 중간값보다 많은 경우
if (smaller[i] >= mid)
ans++;
}
System.out.println(ans);
}
}
'문제 풀이 > Baekjoon' 카테고리의 다른 글
[백준] S1 16174번 점프왕 쩰리 (Large) (JAVA) (0) | 2022.08.01 |
---|---|
[백준] S1 14940번 쉬운 최단거리 (JAVA) (0) | 2022.07.31 |
[백준] S2 14248번 점프 점프 (JAVA) (0) | 2022.07.24 |
[백준] G2 1103번 게임 (JAVA) (0) | 2022.07.21 |
[백준] S2 21736번 헌내기는 친구가 필요해 (JAVA) (0) | 2022.07.19 |