문제
모양은 같으나, 무게가 모두 다른 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
5 4
2 1
4 3
5 1
4 2
예제 출력 1
2
소스코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
private static BufferedReader br;
private static StringTokenizer st;
private static int N, M, num, result=0;
private static int []cntL, cntH;
private static boolean []visitedL, visitedH;
private static List<Integer> []light, heavy;
public static void main(String[] args) throws IOException {
br=new BufferedReader(new InputStreamReader(System.in));
st=new StringTokenizer(br.readLine());
N=Integer.parseInt(st.nextToken());
M=Integer.parseInt(st.nextToken());
num=N/2;
light=new ArrayList[N+1]; // 자신보다 가벼운 구슬 저장
for(int i=1;i<=N;i++) light[i]=new ArrayList<>();
heavy=new ArrayList[N+1]; // 자신보다 무거운 구슬 저장
for(int i=1;i<=N;i++) heavy[i]=new ArrayList<>();
cntL=new int[N+1]; // 자신보다 가벼운 구슬의 최소 개수
cntH=new int[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());
if(!light[a].contains(b)) light[a].add(b);
if(!heavy[b].contains(a)) heavy[b].add(a);
}
for(int i=1;i<=N;i++) {
visitedL=new boolean[N+1]; // 자신보다 확실히 가벼운 구슬의 개수 탐색
visitedL[i]=true;
dfsL(i, i);
visitedH=new boolean[N+1]; // 자신보다 확실히 무거운 구슬의 개수 탐색
visitedH[i]=true;
dfsH(i, i);
}
for(int i=1;i<=N;i++) {
if(cntL[i]>num) result++;
if(cntH[i]>num) result++;
}
System.out.println(result);
}
private static void dfsL(int start, int x) {
if(light[x].size()==0) return;
for(int i:light[x]) {
if(!visitedL[i]) {
visitedL[i]=true;
cntL[start]++;
dfsL(start, i);
}
}
}
private static void dfsH(int start, int x) {
if(heavy[x].size()==0) return;
for(int i:heavy[x]) {
if(!visitedH[i]) {
visitedH[i]=true;
cntH[start]++;
dfsH(start, i);
}
}
}
}
M개의 쌍이 같은 값이 들어올 수도 있다는 것을 고려하지 못하여 계속 틀렸던 문제입니다.
1번부터 N번까지 각 구슬에 대하여 자신보다 확실히 가벼운 구슬과 무거운 구슬의 개수를 각각 구하여,
해당 값이 (N-1)/2 보다 크면 무게가 중간이 될 수 없습니다.
'코딩테스트 > 그래프 탐색' 카테고리의 다른 글
[Java] 백준 12851번 : 숨바꼭질 2 (0) | 2022.05.11 |
---|---|
[Java] 백준 2660번 : 회장뽑기 (0) | 2022.05.11 |
[Java] 백준 15900번 : 나무 탈출 (0) | 2022.05.10 |
[Java] 백준 14716번 : 현수막 (0) | 2022.05.10 |
[Java] 백준 12852번 : 1로 만들기 2 (0) | 2022.05.09 |