JAVA/문제 풀이

[백준 / BOJ] 19541번 : 역학 조사 - JAVA

ahue 2023. 9. 24. 17:32
728x90

https://www.acmicpc.net/problem/19541

 

19541번: 역학 조사

2020년, 신종 전염병이 유행하여 UCPC국 질병관리본부에서 역학 조사를 하고 있다. UCPC국의 인구는 총 $N$명이며 각각 $1$, $2$, $\cdots$, $N$번의 주민번호가 붙어있다. 질병관리본부는 지금까지 $M$개의

www.acmicpc.net

기본 아이디어

문제를 보고 가장 먼저 떠올린 것을 가장 마지막 모임부터 거꾸로 올라가면서 병이 전염된 모임을 찾는 것이었다. 모든 참가자가 병에 걸려있다면 해당 모임에서 전염병에 걸렸다고 가정하고, 한 명이라도 병에 걸려 있지 않으면 그 모임이 시작하기 전까지는 해당 모임의 참가자가 병에 걸리지 않은 것이다.

 

즉, 정리하면 다음과 같다.

1. N번째 모임의 참가자가 모두 전염병에 걸려있다면 해당 모임이 시작하기 전 해당 참가자들은 모두 전염병에 걸려 있었다고 가정한다.
2. N번째 모임의 참가자 중 한 명이라도 전염병에 걸려 있지 않다면 해당 모임이 시작하기 전 해당 참가자들은 모두 전염병에 걸려있지 않았다고 가정한다.

이를 통해 모임을 M - 1번째부터 0번째까지 거슬러 올라가며 최초 감염자를 찾고, 만일 최초 감염자가 없다면 NO를 출력했다. 단, 이렇게만 코드를 짜면 시작하자마자 틀리고 만다.

 

반례

내가 겪은 반례는 다음과 같다.

#1 
3 1
2 1 2
1 0 1

정답 :
NO

#2
3 1
2 1 2
1 1 1

정답 :
YES
1 1 1

#3
4 2
2 1 2
2 3 4
1 0 1 1

정답 :
NO

#4
4 1
3 1 2 3
0 0 0 0

정답 :
YES
0 0 0 0

 

위 반례를 고려하여 다음과 같은 절차를 추가했다.

3. N번째 모임의 참여자가 모두 전염병에 걸렸다면, 참여자가 전염병에 걸린 모임을 나타내는 order 배열의 값을 N으로 업데이트 한다. (order 배열은 최초에 -1로 초기화한다.)
    3 - 1. 최종 감염자인 사람 i의 order[i] 값이 -1이고, 모임에 참여한 적이 있다면(v[i]가 true라면) 해당 참여자가 전염병에 걸린 모임을 찾을 수 없으므로 "NO"를 출력한다.

3 - 1 조건을 넣은 이유는, 최종 감염자이지만 모임에 한 번도 참여를 안했다면 그냥 처음부터 걸려 있었을 것이기 때문이다. 따라서 모임에 참여를 한 번도 하지 않은 사람은 최초 감염자를 찾을 때 제외하고 생각해야 한다.

 

전체 코드

public class Main {

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		int N = Integer.parseInt(st.nextToken());
		int M = Integer.parseInt(st.nextToken());
		
		List<Integer>[] list = new ArrayList[M];
		boolean[] v = new boolean[N];
		for (int i = 0; i < M; i++) {
			list[i] = new ArrayList<>();
			st = new StringTokenizer(br.readLine());
			int K = Integer.parseInt(st.nextToken());
			for (int j = 0; j < K; j++) {
				int a = Integer.parseInt(st.nextToken()) - 1;
				list[i].add(a);
				v[a] = true;
			}
		}
		
		int[] covid = new int[N];
		int[] origin = new int[N];
		st = new StringTokenizer(br.readLine());
		for (int i = 0; i < N; i++) {
			covid[i] = Integer.parseInt(st.nextToken());
			origin[i] = covid[i];
		}
		
		int[] order = new int[N];
		Arrays.fill(order, -1);
		for (int i = M - 1; i >= 0; i--) {
			boolean flag = true;
			for (int j : list[i]) {
				if(origin[j] == 0) {
					for (int k : list[i]) {
						origin[k] = 0;
					}
					flag = false;
					break;
				}
			}
			if(flag) {
				for (int j : list[i]) {
					order[j] = i;
				}
			}
		}
		
		StringBuilder sb = new StringBuilder();
		sb.append("YES\n");
		for (int i = 0; i < N; i++) {
			if(covid[i] == 1 && order[i] == -1 && v[i]) {
				System.out.println("NO");
				return;
			}
			sb.append(origin[i]).append(" ");
		}
		System.out.println(sb);
		
	}

}
반응형