티스토리 뷰

알고리즘/백준

(백준) 신년 파티 _ 1623

구름뭉치 2022. 4. 1. 17:22

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

 

🐢 설명

트리DP + 트래킹 문제이다.

 

문제를 정리해보면 자신의 직속상사가 참가하면 자신은 참가하지 않고, 직속상사가 불참하면 자신은 참가할 수 있으며 && 참가자들의 날나리 정도의 합이 최대가 되도록 하는 멤버 및 그때의 날나리 합을 구하면 된다. 근데 이때 사장이 참여하는 경우 / 참여하지 않는 경우 2가지에 대해 구해야 한다.

 

먼저, 상사의 참가여부에 부하의 참가여부가 달라지는 경우는 일반적인 트리 DP 문제로 2차원 dp배열을 통해 풀 수 있다.

  • 상사가 참여하는 경우
    • 부하는 참여하지 못함
  • 상사가 참여하지 않는 경우
    • 부하는 참여하거나
    • 부하는 참여하지 않음

이렇게 케이스를 나눠서 dp를 채워주면 된다.

 

하지만 이 문제에서는 추가적으로 참여하는 멤버를 뽑아줘야 하므로 추적을 위해 check[]을 추가로 필요로 한다. dp배열을 채울 때

참가일 경우 check[true]로 하고, 참가하지 않을 경우 check[false]를 해주면 된다.

 

이후 dfs로 탐색이 종료되고 난 후 사장 참여하는 경우 / 안하는 경우 나눠서 trace리스트를 check배열을 확인하면서 채워준다. 이때 상관이 참여하지 않는다고 해서 부하가 바로 참여하는게 아니라, check배열에서 더 이득이 되는 경우를 따져서 체크해주었으므로 trace를 채울 때도 상관이 불참일 때 부하의 참여여부를 보고 넣어줘야 한다. 

 

🐢코드
public class Main {
	static int N;
	static int[][] dp;
	static int YES = 0;
	static int NO = 1;
	static ArrayList<Integer> adj[];
	static ArrayList<Integer> trace;
	static boolean[] check;

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;

		N = Integer.parseInt(br.readLine());
		dp = new int[2][N + 1];
		adj = new ArrayList[N + 1];
		check = new boolean[N + 1];

		st = new StringTokenizer(br.readLine());
		for (int i = 1; i < N + 1; i++) {
			adj[i] = new ArrayList<>();
			dp[YES][i] = Integer.parseInt(st.nextToken());
		}

		st = new StringTokenizer(br.readLine());
		for (int i = 2; i < N + 1; i++) {
			int boss = Integer.parseInt(st.nextToken());
			adj[boss].add(i);
		}

		StringBuilder answer = new StringBuilder();
		trace = new ArrayList<>();

		dfs(1);
		answer.append(dp[YES][1]).append(" ").append(dp[NO][1]).append("\n");

		// 사장이 참여할 때 참가자 추적
		traceDfs(1, YES);
		trace.sort(null);
		for (Integer t : trace) {
			answer.append(t).append(" ");
		}
		answer.append("-1").append("\n");

		// 사장이 불참할 때 참가자 추적
		trace.clear();
		traceDfs(1, NO);
		trace.sort(null);
		for (Integer t : trace) {
			answer.append(t).append(" ");
		}
		answer.append("-1");

		System.out.println(answer);
	}

	private static void dfs(int root) {
    	// 일단 상사는 참여한다고 체크
		for (Integer child : adj[root]) {
			dfs(child);
			dp[YES][root] += dp[NO][child];
			check[root] = true;

			// 부하가 참여하는거가 이득이면 부하가 참여한다고 체크
			if (dp[YES][child] >= dp[NO][child]) {
				check[child] = true;
				dp[NO][root] += dp[YES][child];
			} else {
			// 부하가 불참하는거가 이득이면 부하가 불참한다고 체크
				check[child] = false;
				dp[NO][root] += dp[NO][child];
			}
		}
	}

	private static void traceDfs(int root, int isCome) {
		if (isCome == YES) {
			trace.add(root);
		}

		for (Integer child : adj[root]) {
        	// 상사가 참여면 부하는 무조건 불참
			if (isCome == YES) {
				traceDfs(child, NO);
			} else {
            	// 상사가 불참이면 부하는 참여여부를 보고 참여
				if (check[child]) traceDfs(child, YES);
				else traceDfs(child, NO);
			}
		}
	}
}
🐢 마무리
반응형

'알고리즘 > 백준' 카테고리의 다른 글

(백준) 트리 _ 4256  (0) 2022.04.04
(백준) 스크루지 민호 2 _ 12978  (0) 2022.04.01
(백준) 망가진 나무 _ 24232  (0) 2022.03.31
(백준) 프린트전달 _ 23887  (0) 2022.03.30
(백준) 트리의 독립집합 _ 2213  (0) 2022.03.27
Comments
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday