ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 1949 - 우수 마을
    Algorithm/Graph 2024. 3. 5. 15:13
    728x90

    1949번: 우수 마을 (acmicpc.net)

     

    1949번: 우수 마을

    N개의 마을로 이루어진 나라가 있다. 편의상 마을에는 1부터 N까지 번호가 붙어 있다고 하자. 이 나라는 트리(Tree) 구조로 이루어져 있다. 즉 마을과 마을 사이를 직접 잇는 N-1개의 길이 있으며,

    www.acmicpc.net

     

    문제

    N개의 마을로 이루어진 나라가 있다. 편의상 마을에는 1부터 N까지 번호가 붙어 있다고 하자. 이 나라는 트리(Tree) 구조로 이루어져 있다. 즉 마을과 마을 사이를 직접 잇는 N-1개의 길이 있으며, 각 길은 방향성이 없어서 A번 마을에서 B번 마을로 갈 수 있다면 B번 마을에서 A번 마을로 갈 수 있다. 또, 모든 마을은 연결되어 있다. 두 마을 사이에 직접 잇는 길이 있을 때, 두 마을이 인접해 있다고 한다.

    이 나라의 주민들에게 성취감을 높여 주기 위해, 다음 세 가지 조건을 만족하면서 N개의 마을 중 몇 개의 마을을 '우수 마을'로 선정하려고 한다.

    1. '우수 마을'로 선정된 마을 주민 수의 총 합을 최대로 해야 한다.
    2. 마을 사이의 충돌을 방지하기 위해서, 만일 두 마을이 인접해 있으면 두 마을을 모두 '우수 마을'로 선정할 수는 없다. 즉 '우수 마을'끼리는 서로 인접해 있을 수 없다.
    3. 선정되지 못한 마을에 경각심을 불러일으키기 위해서, '우수 마을'로 선정되지 못한 마을은 적어도 하나의 '우수 마을'과는 인접해 있어야 한다.

    각 마을 주민 수와 마을 사이의 길에 대한 정보가 주어졌을 때, 주어진 조건을 만족하도록 '우수 마을'을 선정하는 프로그램을 작성하시오.

    입력

    첫째 줄에 정수 N이 주어진다. (1 ≤ N ≤ 10,000) 둘째 줄에는 마을 주민 수를 나타내는 N개의 자연수가 빈칸을 사이에 두고 주어진다. 1번 마을부터 N번 마을까지 순서대로 주어지며, 주민 수는 10,000 이하이다. 셋째 줄부터 N-1개 줄에 걸쳐서 인접한 두 마을의 번호가 빈칸을 사이에 두고 주어진다.

    출력

    첫째 줄에 '우수 마을'의 주민 수의 총 합을 출력한다.

    예제 입력 1 복사

    7
    1000 3000 4000 1000 2000 2000 7000
    1 2
    2 3
    4 3
    4 5
    6 2
    6 7
    

    예제 출력 1 복사

    14000

     

     

    문제에 생각보다 조건이 많다. 문제 자체를 보면 dfs로 해결하는 문제처럼 보이지만, 상당히 시간복잡도가 걸릴 것으로 생각이 되어, dp로 해결하게 되었다.

     

    먼저, v가 우수마을일 때와 우수마을이 아닐 때를 구분해야한다.

     

    dp[v][0] : 마을 v가 우수마을 X -> v와 자손 노드들로부터 얻을 수 있는 최대 주민 수

    dp[v][1] : 마을 v가 우수마을 O -> v와 자손 노드들로부터 얻을 수 있는 최대 주민 수

     

    dp테이블을 이와 같이 작성한 상태에서, 알고리즘을 떠올려보자.

     

    v가 우수마을이 아닐 때 자식 u는 우수마을 일 수도, 우수마을이 아닐 수도 있다. 또한, v가 우수마을일 경우에는 자식 u는 우수마을일 수 없다.

     

    이것이 핵심 알고리즘이다. 이제 그렇다면 코드를 작성해보자.

    1. 먼저 필요한 것은 입력을 받을 리스트들이므로, n, population, tree를 작성해서 tree에 u와 v를 입력받아 골고루 담아준다.

    2. dp 테이블을 [0,0]으로 초기화한다.

    3. visited 리스트를 False를 초기값으로 설정한다.

    4. dfs 알고리즘 : v를 방문한 후, u(자식 노드)는 방문하지 못했을 때, dfs(u)로 방문시켜 주고, dp[v][0]과 dp[v][1]을 설정해준다. dp[v][0]은 max값으로 설정해서 우수마을 일 때, 우수마을이 아닐 때를 비교시켜준다. dp[v][1]은 v가 우수마을일 때 이므로, u는 우수마을일 수 없기 때문에, dp[u][0]의 값을 그대로 더해준다.

    5. 루트노드(1번 마을)을 dfs(1)로 호출시켜준다.

    6. 1번 마을이 우수마을인지, 아닌지를 비교하고 우수마을일때를 max로 최댓값을 뽑아준다.

     

    # dp[v][0] : 마을 v가 우수마을 X -> v와 자손 노드들로부터 얻을 수 있는 최대 주민 수
    # dp[v][1] : 마을 v가 우수마을 O -> v와 자손 노드들로부터 얻을 수 있는 최대 주민 수
    # v가 우수마을 X -> 자식 u는 우수마을 or 우수마을 X 모두 가능
    # v가 우수마을 O -> 자식 u는 우수마을 X
    # 우수마을 선정 시 + 우수마을 선정 X 시의 최대 주민 수 비교해서 max 값
    
    import sys
    input = sys.stdin.readline
    sys.setrecursionlimit(10**7)
    n = int(input())
    population = 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 = [False for _ in range(n+1)]
    
    def dfs(v):
        visited[v] = True
        dp[v][0] = 0
        dp[v][1] = population[v-1]
        for u in tree[v]:
            if not visited[u]:
                dfs(u)
                dp[v][0] += max(dp[u][0], dp[u][1])   # v가 우수마을이 아닐 때
                dp[v][1] += dp[u][0] # v가 우수마을이 일 때
    
    dfs(1) # 루트노드(1번 마을)
    print(max(dp[1][0], dp[1][1]))
    728x90

    'Algorithm > Graph' 카테고리의 다른 글

    백준 14502 - 연구소  (0) 2024.04.04
    백준 1174 - 우주신과의 교감  (0) 2024.01.14
    백준 1956 - 운동  (1) 2024.01.07
Designed by Tistory.