-
[BOJ/python]2213번 트리의 독립집합알고리즘/BOJ 2022. 7. 6. 22:46
백준 2213번 트리의 독립집합 파이썬
출처 - https://www.acmicpc.net/problem/2213
트리에서 DP를 사용하는 문제였다. 독립집합의 크기를 구하는 것은 쉽게 생각할 수 있었다. 백준 트리DP 알고리즘 분류에서 가장 위에 있는 SNS 문제와 거의 유사했다. 경로를 구하기 위해서 따로 추적을 하는 함수를 작성했는데 간단하게 만드는 방법도 존재할 것 같다.
1. 풀이
1. 최대값 구하기
트리의 독립집합에 포함될 노드를 가중치를 비교하며 선택해가면 된다. 가장 먼저 트리의 독립집합을 구하기 위해서 트리의 부모-자식 관계를 설정해야 한다.
임의의 노드를 루트 노드로 설정해도 트리의 특성은 유지된다. 즉 인접 리스트로 트리를 저장한 뒤 방문 표시를 하며 루트부터 순회하면 자식 노드를 차례대로(DFS) 모두 방문할 수 있다.
- 부모 노드를 선택했다면 자식 노드는 선택할 수 없다. 부모 노드를 선택하지 않았다면 자식 노드는 선택’할 수’ 있다. (반드시 자식 노드를 선택한 경우가 큰 것은 아니다)
- 즉 dp 테이블을 2차원으로 만들고 해당 노드를 선택한 경우에 누적된 독립집합의 크기와 선택하지 않은 경우의 크기를 모두 저장한다.
2. 경로 구하기
- dp 테이블에 2가지 경우가 저장되어 있으므로 이를 이용해서 추적한다.
- 재귀함수를 이용하여 방문할 노드와 방문할 노드의 부모 노드가 선택되었는 지 여부를 전달한다. 해당 노드가 선택되었다면 check 배열을 통해 표시한다.
- 만약 현재 노드를 선택한 경우에 독립집합의 크기가 크다면 방문하지 않은 자식 노드와 함께 재귀함수에 1을 전달하여 자식 노드는 선택할 수 없음을 표시한다. (ps=1일 때 무조건 check=0)
- 만약 현재 노드를 선택하지 않은 경우에 독립집합의 크기가 크다면 재귀함수에 0을 전달한다.
- 이 때 자식 노드가 입력값으로 함수가 실행될 때는 노드가 선택된 경우 혹은 선택 되지 않은 경우 비교가 가능하다. (ps=0일 때 두 가지 경우로 분기처리)
2. 코드
N = int(input()) W = [0]+ list(map(int, input().split())) tree = [[] for _ in range(N+1)] for _ in range(N-1): u,v = map(int,input().split()) tree[u].append(v) tree[v].append(u) dp=[ [0,0] for _ in range(N+1) ] visited = [0 for _ in range(N+1)] def dynamic(node): if visited[node] == 1: return max(dp[node][0], dp[node][1]) visited[node]=1 dp[node][1]=W[node] for child in tree[node]: if visited[child]==0: dynamic(child) dp[node][0] += max(dp[child][1], dp[child][0]) dp[node][1] += dp[child][0] return max(dp[node][0], dp[node][1]) result = dynamic(1) check = [0 for _ in range(N+1)] visited = [0 for _ in range(N+1)] def findPath(node,ps): if visited[node]==1: return visited[node]=1 if ps==1: check[node]=0 for child in tree[node]: if visited[child]==0: findPath(child, 0) else: if dp[node][0]> dp[node][1]: check[node]=0 for child in tree[node]: if visited[child]==0: findPath(child,0) else: check[node]=1 for child in tree[node]: if visited[child]==0: findPath(child,1) findPath(1, 0) print(result) for i in range(N+1): if check[i]==1: print(i, end=' ')
'알고리즘 > BOJ' 카테고리의 다른 글
[BOJ/python]1261번 알고스팟 (0) 2022.07.06 [BOJ/python]11375번 열혈강호 (0) 2022.07.06 [BOJ/python]2208번 보석줍기 (0) 2022.07.06 [BOJ/python]10211번 Maximum Subarray (0) 2022.07.06 [BOJ/python]1504번 특정한 최단 경로 (0) 2022.07.06