[ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค] ๋งค์ถœ ํ•˜๋ฝ ์ตœ์†Œํ™” / ํŒŒ์ด์ฌ / DP
Problem Solving ๐Ÿ”ฅ/ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค

[ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค] ๋งค์ถœ ํ•˜๋ฝ ์ตœ์†Œํ™” / ํŒŒ์ด์ฌ / DP

programmers.co.kr/learn/courses/30/lessons/72416

ํ™•์‹คํžˆ ์–ด๋ ต๋„ค์š”..

๊ฐœ์ธ์ ์œผ๋กœ 2021 ์นด์นด์˜ค ๋ฌธ์ œ์ค‘ ๊ฐ€์žฅ ์–ด๋ ค์› ๊ณ , ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ณต๋ถ€๋ฅผ ์—ด์‹ฌํžˆ ํ•ด์•ผ๊ฒ ๋‹ค๊ณ  ๋А๊ผˆ๋˜ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค..

DP๋ฌธ์ œ์ธ๋ฐ, ์ƒ๊ฐ๋ณด๋‹ค ๊ตฌํ˜„๋ฐฉ๋ฒ•์ด ์ž˜ ์•ˆ๋– ์˜ฌ๋ผ ๋‹ต์•ˆ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์šฐ์„  Root๋Š” 1๋ฒˆ์ด๋‹ˆ, 1๋ฒˆ๋ถ€ํ„ฐ ํƒ์ƒ‰์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ผ€์ด์Šค๋Š” ๋‘๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค

1) dp[n][1] => n๋ฒˆ ์‚ฌ๋žŒ์ด ์„ ๋ฐœ๋˜๋Š” ๊ฒฝ์šฐ
2) dp[n][0] => n๋ฒˆ ์‚ฌ๋žŒ์ด ์„ ๋ฐœ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

1๋ฒˆ ์ผ€์ด์Šค์˜ ๊ฒฝ์šฐ์—๋Š” ์‰ฝ๊ฒŒ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ์š”. n๋ฒˆ์˜ ๋งค์ถœ์•ก์„ ๋”ํ•˜๊ณ  n๋ฒˆ์˜ ์ž์‹๋“ค์ด ์„ ๋ฐœ์ด ๋˜๋“ , ์•ˆ๋˜๋“  ์ตœ์†Œ๊ฐ’๋งŒ ์„ ํƒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

2๋ฒˆ ์ผ€์ด์Šค์˜ ๊ฒฝ์šฐ ์กฐ๊ธˆ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค.
n๋ฒˆ์˜ ๋งค์ถœ์•ก์„ ๋”ํ•˜์ง€ ์•Š๊ณ , n๋ฒˆ์˜ ์ž์‹๋“ค์ด ์„ ๋ฐœ์ด ๋˜๋“ , ์•ˆ๋˜๋“  ์ตœ์†Œ๊ฐ’๋งŒ์„ ์„ ํƒํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ, ๋ชจ๋“  ์ž์‹๋“ค์ด ์„ ๋ฐœ๋˜์ง€ ์•Š๋Š” ์ผ€์ด์Šค๋Š” ์—†์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค!

๊ทธ ๊ฒฝ์šฐ๋ฅผ flag๋ฅผ ์ฃผ์–ด์„œ ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.
๋งŒ์•ฝ ๋ชจ๋“  ์ž์‹๋“ค์ด ์„ ๋ฐœ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ๋ฐฉ๋ฌธํ•œ ๊ฒฝ์šฐ์™€, ๋ฐฉ๋ฌธ์„ ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์˜ ์ฐจ์ด๊ฐ’์ด ๊ฐ€์žฅ ์ž‘์€ ๋…€์„์„ ์„ ํƒํ•ด์ค๋‹ˆ๋‹ค.
์™œ๋ƒ๋ฉด ๊ทธ ๊ฒฝ์šฐ๊ฐ€ ๋งค์ถœ์•ก ์†ํ•ด๊ฐ€ ๊ฐ€์žฅ ์ ์€ ๊ฒฝ์šฐ์ด๊ฑฐ๋“ ์š”.

๋ง์„ ํ•˜๊ธฐ๋Š” ์‰ฌ์šด๋ฐ, ๋ง‰์ƒ ์ฝ”๋“œ๋ฅผ ์งœ๋ฉด ๋˜ ์–ด๋ ค์šด ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜๋„ ์ฝ”๋“œ๋ฅผ ๋ณด์‹œ๋ฉด ์ดํ•ดํ•˜์‹ค ์ˆ˜ ์žˆ์œผ์‹ค ๊ฒƒ์ž…๋‹ˆ๋‹ค.

from copy import deepcopy
import sys

cost = None
dp = None
tree = None
INF = sys.maxsize

# n๋ฒˆ์ด ์„ ๋ฐœ๋˜๋Š” ๊ฒฝ์šฐ, ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ
def dfs(n, include):
    global cost, dp, tree

    if dp[n][include] != -1:
        return dp[n][include]

    ret = 0
    if include:
        ret = cost[n]
        for child in tree[n]:
            c_cost = min(dfs(child, 0), dfs(child, 1))
            ret += c_cost
        # print(n, include, ret)
        dp[n][include] = ret
        return dp[n][include] 
    else:
        # ๋‚ด๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ํ•˜์œ„์ง์› ์ค‘ ํ•˜๋‚˜๋Š” ๋ฌด์กฐ๊ฑด ์žˆ์–ด์•ผ ํ•จ.
        ans = 0
        diff = 0 if len(tree[n]) == 0 else INF
        # ์ž์‹์ด ๋ชจ๋‘ ์ฐธ์—ฌ ์•ˆํ•˜๋ฉด, flag = False
        flag = False

        for child in tree[n]:
            cost1 = dfs(child, 1)
            cost2 = dfs(child, 0)
            # ๋ฐฉ๋ฌธํ•œ ์ฝ”์ŠคํŠธ๊ฐ€ ๋ฐฉ๋ฌธ์•ˆํ•œ ์ฝ”์ŠคํŠธ๋ณด๋‹ค ์ž‘๋‹ค => ์ž์‹ ์ค‘ ๋ฐฉ๋ฌธํ•œ ์ผ€์ด์Šค๊ฐ€ ์กด์žฌํ•จ์„ ์˜๋ฏธ, flag = True
            if cost1 < cost2:
                flag = True
            else:
                diff = min(cost1 - cost2, diff) 
            ans += min(cost1, cost2)
        ret = ans if flag else diff + ans
        dp[n][include] = ret
        return dp[n][include] 

def solution(sales, links):
    global dp, tree, cost
    answer = 0
    sales = [-1] + sales
    cost = sales 
    tree = [[] for _ in range(len(sales))]
    dp = [[-1, -1] for _ in range(len(sales))]
    # dp[n][1] n๋ฒˆ์ด ์„ ๋ฐœ๋˜๋Š” ๊ฒฝ์šฐ
    # dp[n][0] n๋ฒˆ์ด ์„ ๋ฐœ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

    for p, c in links:
        tree[p].append(c)

    return min(dfs(1,1), dfs(1, 0))