문제
1949번: 우수 마을
첫째 줄에 정수 N이 주어진다. (1≤N≤10,000) 둘째 줄에는 마을 주민 수를 나타내는 N개의 자연수가 빈칸을 사이에 두고 주어진다. 1번 마을부터 N번 마을까지 순서대로 주어지며, 주민 수는 10,000
www.acmicpc.net
풀이
n번 마을을 우수 마을로 선정하면 인접한 마을은 모두 우수 마을로 선정할 수 없다.
또한, n번 마을을 우수 마을로 선정하지 않은 상태에서 인접한 마을을 모두 우수 마을로 선정하는 것이 최적해를 보장하지는 않는다.
이 문제는 서브트리의 가중치의 합을 구하는 문제이다. 이를 dfs와 동적계획법으로 풀 수 있다.
dp[n][1]은 n번 마을을 우수마을로 선정했을 경우에 우수 마을의 주민 수의 총합이다.
dp[n][0]은 n번 마을을 우수마을로 선정하지 않았을 경우에 우수 마을의 주민 수의 총합이다.
- dfs) u번 마을을 방문하지 않았다면 u번 마을을 방문한다.
- n번 마을을 선정했을 경우 인접한 u번 마을을 선정할 수 없다.
- dp[n][1] += dp[u][0]
- n번 마을을 선정하지 않은 경우 인접한 u번 마을을 선정하거나 선정하지 않는 두 가지 경우를 모두 고려해야 한다.
- dp[n][0] += max(dp[u][0], dp[u][1])
결국 재귀적으로 서브트리의 가중치의 합이 구해지게 되며, 이를 통해 답을 구할 수 있다.
코드
import sys, collections
sys.setrecursionlimit(10**6)
def dfs(cur):
visited[cur] = 1
for u in g[cur]:
if not visited[u]:
dfs(u)
dp[cur][1] += dp[u][0] # 현재 마을을 우수마을로 선정
dp[cur][0] += max(dp[u][0], dp[u][1]) # 현재 마을을 우수마을로 선정 X
n = int(sys.stdin.readline().strip())
cost = [0] + [int(x) for x in sys.stdin.readline().split()]
visited = [0 for _ in range(n+1)]
dp = [[0, cost[i]]*2 for i in range(n+1)] # dp[i][0] = i마을을 선정X, dp[i][1] = i마을을 선정O
g = collections.defaultdict(list)
for _ in range(n-1):
v, u = map(int, sys.stdin.readline().split())
g[v].append(u)
g[u].append(v)
dfs(1)
print(max(dp[1][1], dp[1][0]))
'CS > 알고리즘 문제 풀이' 카테고리의 다른 글
[백준] 10819 - 차이를 최대로 [Python(파이썬)] (0) | 2021.01.23 |
---|---|
[백준] 1929 - 소수구하기 [Python(파이썬)] (0) | 2021.01.23 |
[백준] 1991 - 트리순회 [Python(파이썬)] (0) | 2021.01.20 |
[백준] 1912 - 연속합 [Python(파이썬)] (0) | 2021.01.19 |
[백준] 11403 - 경로 찾기 [Python(파이썬)] (0) | 2021.01.16 |