Skip to content

Conversation

@tgyuuAn
Copy link
Member

@tgyuuAn tgyuuAn commented Jun 3, 2024

πŸ”— 문제 링크

개미

βœ”οΈ μ†Œμš”λœ μ‹œκ°„

2μ‹œκ°„

μ§„μ§œ... 문제 λΆ„λ₯˜ μ•ˆλ³΄κ³ ... λ ˆνΌλŸ°μŠ€λ„ μ•ˆλ³΄κ³ ...

μ„œμšΈ -> λΆ€μ‚°κ°€λŠ” itxμ—μ„œ 5μ‹œκ°„λ™μ•ˆ ν•  것도 μ—†κ³  ν•΄μ„œ... ν•«μŠ€νŒŸ ν‚€κ³  λ…ΈνŠΈλΆ νŽΌμ³μ„œ ν’€μ—ˆλŠ”λ°

λ””μŠ€μ½”λ“œμ—μ„œ κ³ κ΅°λΆ„νˆ¬ ν•˜λ©΄μ„œ 원큐에 ν’€μ—ˆμ–΄μš”... 🫑🫑🫑

μ§„μ§œ... μ™„μ „ μ§œλ¦Ών•΄..

image

✨ μˆ˜λ„ μ½”λ“œ

근데 문제 ν’€κ³ λ‚˜μ„œ μ•Œκ³ λ¦¬μ¦˜ λΆ„λ₯˜λ₯Ό λ³΄λ‹ˆκΉŒ ν¬μ†Œ 배열이라고 ν•˜λ„€μš”.

일단 μ €λŠ” κ·Έλ ‡κ²Œ μ•ˆ ν’€μ—ˆκ΅¬ λ‹€μ΅μŠ€νŠΈλΌ + 이뢄 탐색 으둜 ν’€μ—ˆμ”λ‹ˆλ‹€!







일단 문제λ₯Ό μžμ„Ένžˆ 보면,

κ°œλ―ΈλŠ” μ§‘μ§“κΈ°μ˜ 달인이기 λ•Œλ¬Έμ— λΆˆν•„μš”ν•œ ꡴은 μ§“μ§€ μ•ŠλŠ”λ‹€.

κ·Έλž˜μ„œ ꡴을 타고 ν•œ λ°©μ—μ„œ λ‹€λ₯Έ 방으둜 갈 수 μžˆλŠ” κ²½λ‘œλŠ” 항상 μ‘΄μž¬ν•˜λ©° μœ μΌν•˜λ‹€.

μž„μ˜μ˜ 두 λ°© μ‚¬μ΄μ˜ κ±°λ¦¬λŠ” 두 개의 방을 μ—°κ²°ν•˜λŠ” 경둜λ₯Ό κ΅¬μ„±ν•˜λŠ” ꡴의 길이의 합이닀.

방의 κ°œμˆ˜λŠ” n이고, κ°„μ„ μ˜ κ°œμˆ˜λŠ” n-1이닀.

λΌλŠ” μ§€λ¬Έμ—μ„œ κ°œλ―Έκ΅΄μ€ μ•„λž˜μ™€ 같은 ν˜•νƒœλ‘œ λ§Œλ“€μ–΄μ ΈμžˆμŒμ„ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

image







λ˜ν•œ,

μžμ—°μˆ˜ n이 μ£Όμ–΄μ§„λ‹€. n은 방의 κ°œμˆ˜μ΄λ‹€. (1 ≀ n ≀ 10^5)

μ—μ„œ $O(n^2)$ 의 μ‹œκ°„λ³΅μž‘λ„μΈ μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•˜λ©΄ 1얡이 ν›Œμ© λ„˜μ–΄λ²„λ¦¬λ‹ˆ,

μ΅œλŒ€ $O(n * log(n))$ 의 μ‹œκ°„λ³΅μž‘λ„λ‘œ ν’€μ–΄μ•Ό 함을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.







μ²˜μŒμ—λŠ”, AlgoLeadMe/AlgoLeadMe-6#2 문제 처럼,

1번 κ°œλ―Έκ΅΄μ—μ„œ λ‹€μ΅μŠ€νŠΈλΌ ν•œ 번 돌리면 $O(n * log(n))$ 으둜 ν’€ 수 μžˆμ–΄μ„œ κ°œκΏ€ 아냐 ...? ν–ˆλŠ”λ°,

image

μ˜€μ‚°μ΄μ—ˆμ”λ‹ˆλ‹€.







이제 뭐 λͺ¨λ“  κ°œλ―Έκ°€ 체λ ₯이 λ¬΄ν•œμ΄μ–΄μ„œ λͺ¨λ‘ 1번 λ°©κΉŒμ§€ 갈 수 있으면 OK μ˜€κ² μ§€λ§Œ,

개미의 체λ ₯이 ν•œμ •μ μ΄λΌ 1번 κΉŒμ§€ λ„λ‹¬ν•˜μ§€ λͺ»ν•  수 있고,

이럴 경우 1번과 κ°€μž₯ κ°€κΉŒμš΄ 방의 번호λ₯Ό μ œμΆœν•΄μ•Όλ§Œ ν•΄μš”.

image

그럼 또 μœ„ κ·Έλ¦Ό κΈ°μ€€μ—μ„œ 3번 λ…Έλ“œλ₯Ό κΈ°μ€€μœΌλ‘œ λ‹€μ΅μŠ€νŠΈλΌλ₯Ό λŒλ €μ•Όλ§Œ ν• κΉŒμš” ?

그러면 λͺ¨λ“  λ…Έλ“œμ—μ„œ λ‹€μ΅μŠ€νŠΈλΌλ₯Ό λŒλ¦¬λŠ” κΌ΄μ΄λ‹ˆκΉŒ $O(n * n log(n))$ 이 λ˜λ‹ˆκΉŒ μ‹œκ°„μ΄ ν„°μ§‘λ‹ˆλ‹€!







자자, 이걸 μ–΄λ–»κ²Œ ν•΄κ²°ν•˜λŠλƒ,

μ €λŠ” μ΄λ ‡κ²Œ μ ‘κ·Όν–ˆμŠ΅λ‹ˆλ‹€.

μœ„μ—μ„œ μ–΄μ°¨ν”Ό κ°œλ―Έκ΅΄μ€ λΆˆν•„μš”ν•œ 방을 λ§Œλ“ λ‹€κ³  ν•˜μ§€ μ•Šμ•˜μœΌλ―€λ‘œ,

각 λ…Έλ“œλŠ” 1번 λ°© κΉŒμ§€ κ°€λŠ” κ²½λ‘œκ°€ 단 ν•˜λ‚˜λ°–μ— μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

image







μ˜€μΌ€μ΄ μ˜€μΌ€μ΄.

1번 λ…Έλ“œλΆ€ν„° λ‹€μ΅μŠ€νŠΈλΌλ₯Ό λŒλ¦¬λŠ”κ±° κΉŒμ§€λŠ” λ™μΌν•΄μš”.

image







그리고 μΆ”κ°€μ μœΌλ‘œ λ‹€μ΅μŠ€νŠΈλΌλ₯Ό 돌릴 λ•Œ, λΆ€λͺ¨ λ…Έλ“œμ˜ μ •λ³΄κΉŒμ§€ μ €ν•΄μ€λ‹ˆλ‹€

이 과정은 κ·Έλƒ₯ νž™μ— 넣을 λ•Œ 이전 λ…Έλ“œλ₯Ό λ‹€μŒ λ…Έλ“œμ˜ λΆ€λͺ¨λ‘œ μ„€μ •ν•΄μ£Όλ©΄ λ˜μ–΄μš”.

heap = [(0,1)]
parent = [0 for idx in range(N+1)]

while heap:
    now_cost, now_node = heappop(heap)

    if now_cost >= cost[now_node] and now_node != 1: continue
    cost[now_node] = now_cost
            
    for next_node, next_cost in graph_info[now_node].items():
        if now_cost + next_cost < cost[next_node]:
            heappush(heap, (now_cost + next_cost, next_node))
            parent[next_node] = now_node              # λ°”λ‘œ 이 λΆ€λΆ„ μž…λ‹ˆλ‘μ•„!

image







자 이제 λ‹€ μ™”μ”λ‹ˆλ‹€.

그럼 leaf λ…Έλ“œ (말단 λ…Έλ“œ) 만 κ΅¬ν•˜λ©΄ λΆ€λͺ¨ λ…Έλ“œ 정보λ₯Ό μ΄μš©ν•΄μ„œ ν•΄λ‹Ή κ²½λ‘œμ— λŒ€ν•œ 정보λ₯Ό λͺ¨λ‘ 얻을 수 μžˆμ–΄μš”.

image


image

μœ„ κ·Έλ¦Όκ³Ό 같이

[(8, 15), (5, 10), (2, 5), (1,0)] κ³Ό 같이 ν•΄λ‹Ή 경둜의 λ…Έλ“œ 정보와 μ†Œλͺ¨ν•˜λŠ” 체λ ₯을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.




μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‘₯.

for leaf in leaf_node:
    now_node = leaf
    now_road = deque()

    while now_node != 0:
        now_road.append((now_node, cost[now_node]))
        now_node = parent[now_node]







그럼 μœ„ μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ €λ©΄ leaf λ…Έλ“œκ°€ 무엇인지λ₯Ό μ•Œμ•„μ•Όκ² μ£  ?

leaf λ…Έλ“œλŠ” 잘 보면 ν•΄λ‹Ή λ…Έλ“œμ™€ 이어져 μžˆλŠ” λ…Έλ“œκ°€ 1개 밖에 μ—†λŠ” λ…Έλ“œλ“€μž…λ‹ˆλ‹€.

이 λ•Œ 1번 λ…Έλ“œκ°€ 2번 λ…Έλ“œλž‘λ§Œ μ—°κ²°λ˜μ–΄μžˆλŠ” κ²½μš°λ„ μžˆμœΌλ‹ˆ 1번 λ…Έλ“œλŠ” μ œμ™Έ ν•΄μ€λ‹ˆλ‘₯.

leaf_node = deque()
for node, value in enumerate(neighbor_count):
    if node in (0, 1): continue
    if value == 1: leaf_node.append(node)







μœ„ κΉŒμ§€μ˜ 과정은 λͺ¨λ‘ μ‹œκ°„ λ³΅μž‘λ„ $O(n * log(n)$ 으둜 ν–ˆμŠ΅λ‹ˆλ‹€.

자 이제 그럼 μ•„λž˜ 그림처럼 각 leaf λ…Έλ“œ λ³„λ‘œ κ²½λ‘œκ°€ λͺ¨λ‘ μ™„μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹·

μ•„λž˜ κ·Έλ¦Όμ—μ„œλŠ” leaf λ…Έλ“œκ°€ 4개라 4개의 κ²½λ‘œκ°€ μƒμ„±λ˜μ—ˆμ–΄μš”.

image







이제 μ§„μ§œ λ‹€ μ™”μ–΄μš”.

μ•„κΉŒ μ €μž₯ν•œ 각 leaf λ…Έλ“œ 별 κ²½λ‘œμ—μ„œ [(8, 15), (5, 10), (2, 5), (1,0)]

μ•žμ— ν•­ λΆ€ν„° pop ν•˜λ©΄μ„œ ν˜„μž¬ 방에 μžˆλŠ” 개미의 체λ ₯으둜 μ–΄λ””κΉŒμ§€ 갈 μžˆλŠ” μ§€ 이뢄 νƒμƒ‰μœΌλ‘œ μ°Ύμ•„μ€λ‹ˆλ‹€.




예λ₯Ό λ“€λ©΄ 8번 방에 μžˆλŠ” 개미의 체λ ₯이 10만큼 μžˆλ‹€κ³  ν–ˆμ„ λ•Œ,

2번 λ°©κΉŒμ§€ 갈 수 있겠죠? (8번방 κΉŒμ§€μ˜ 거리가 15이고 2번방 κΉŒμ§€μ˜ 거리가 5μ΄λ‹ˆκΉŒ 15- 5λŠ” 10 μž…λ‹ˆλ‹€.)

μœ„μ™€ 같은 과정을 이뢄 νƒμƒ‰μœΌλ‘œ μ°Ύμ•„μ£ΌλŠ” 것 μž…λ‹ˆλ‘₯.




def check(mid, now_road, energy):
    if now_road[0][1] - now_road[mid][1] <= energy: return True  # λ§Œμ•½ ν˜„μž¬ 개미의 체λ ₯으둜 ν•΄λ‹Ή κ΅΄ κΉŒμ§€ 갈 수 있으면 True
    return False

while now_road:
        now_idx, now_distance = now_road[0]
        now_energy = ant[now_idx-1]

        if answer[now_idx] != 0:
            now_road.popleft()
            continue
        
       # print(now_road)
        
        left = -1
        right = len(now_road)
        temp = 0
        while left+1<right:
            mid = (left+right)//2
            #print(left, mid, right)

            if check(mid, now_road, now_energy):
                temp = mid
                left = mid

            else: right = mid

        answer[now_idx] = now_road[temp][0]
        #print(answer[1:])
        #print()
        now_road.popleft()

이러면 각 λ…Έλ“œ λ³„λ‘œ $O(log(n))$ 의 μ‹œκ°„ λ³΅μž‘λ„λ‘œ ν’€ 수 μžˆμœΌλ‹ˆκΉŒ,

λͺ¨λ“  λ…Έλ“œλ“€ N개 * log(N) ν•˜λ©΄ $O(n*log(n)$으둜 λͺ¨λ“  λ…Έλ“œμ— λŒ€ν•΄μ„œ μ–΄λ””κΉŒμ§€ 뻗을 수 μžˆλŠ”μ§€ λ‹€ ꡬ할 수 μžˆμŠ΅λ‹ˆλ‹€!!

πŸ“š μƒˆλ‘­κ²Œ μ•Œκ²Œλœ λ‚΄μš©

@tgyuuAn tgyuuAn self-assigned this Jun 3, 2024
@tgyuuAn tgyuuAn added tgyuuAn ν•œ μ€„λ‘œλŠ” μ†Œκ°œν•  수 μ—†λŠ” λ‚¨μž. μž‘μ„± 쀑 ⏱️ and removed 리뷰 κΈ°λ‹€λ¦¬λŠ” 쀑 πŸ”₯ labels Jun 3, 2024
@tgyuuAn tgyuuAn removed the request for review from alstjr7437 June 4, 2024 14:36
Copy link
Collaborator

@H0ngJu H0ngJu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 λ¦¬λ·°λŠ” 리뷰가 μ•„λ‹ˆλΌ 감상평에 더 κ°€κΉŒμšΈ 것 κ°™λ„€μš” πŸ˜―πŸ‘πŸ‘

PR을 μ½λŠ”λ° μ•Œκ³ λ¦¬μ¦˜ 짬λ°₯이 ν˜λŸ¬λ‚˜μ˜€λŠ”κ΅°μš” .... γ„·γ„·
항상 자극 λ°›κ³  κ°‘λ‹ˆλ‹€ 🫠

μ•Œκ³ λ¦¬μ¦˜ λΆ„λ₯˜κ°€ ν¬μ†Œ λ°°μ—΄μ΄λΌκΈΈλž˜ ν•œλ²ˆ μ°Ύμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€
ν¬μ†Œ 배열을 μ΄μš©ν•œ 풀이

ν¬μ†Œλ°°μ—΄μ„ ν•œμ€„λ‘œ μ„€λͺ…ν•˜λ©΄
'2^n 번 μ˜¬λΌκ°”μ„ λ•Œμ˜ λ…Έλ“œ μ°ΎκΈ°' 즉, μ–΄λ–€ λ…Έλ“œμ˜ 2^n번째 λΆ€λͺ¨μ°ΎκΈ°μΈ 것 κ°™μ•„μš”.

μ΅œμ†Œκ³΅ν†΅μ‘°μƒ & ν¬μ†Œ λ°°μ—΄
2^n번째 λΆ€λͺ¨μ— λŒ€ν•œ 정보λ₯Ό dp 에 μ €μž₯해두고 μ“°λŠ” 것 κ°™λ„€μš”!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ”•μ…”λ„ˆλ¦¬ 자료ꡬ쑰λ₯Ό 많이 μ•ˆμ¨μ„œ μƒμ†Œν•œλ°

items()κ°€ λ”•μ…”λ„ˆλ¦¬ key, valueλ₯Ό λ°˜ν™˜ν•΄μ£ΌλŠ” ν•¨μˆ˜λ„€μš” 쀍쀍

λ”°λ‘œ μ •μ˜ν•œμ€„ μ•Œκ³  μ°Ύκ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€.. γ…Žγ…Ž

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ«‘πŸ«‘πŸ«‘πŸ‘πŸ»πŸ‘πŸ»πŸ‘πŸ»πŸ‘πŸ»

@tgyuuAn
Copy link
Member Author

tgyuuAn commented Jun 7, 2024

이번 λ¦¬λ·°λŠ” 리뷰가 μ•„λ‹ˆλΌ 감상평에 더 κ°€κΉŒμšΈ 것 κ°™λ„€μš” πŸ˜―πŸ‘πŸ‘

PR을 μ½λŠ”λ° μ•Œκ³ λ¦¬μ¦˜ 짬λ°₯이 ν˜λŸ¬λ‚˜μ˜€λŠ”κ΅°μš” .... γ„·γ„· 항상 자극 λ°›κ³  κ°‘λ‹ˆλ‹€ 🫠

μ•Œκ³ λ¦¬μ¦˜ λΆ„λ₯˜κ°€ ν¬μ†Œ λ°°μ—΄μ΄λΌκΈΈλž˜ ν•œλ²ˆ μ°Ύμ•„λ³΄μ•˜μŠ΅λ‹ˆλ‹€ ν¬μ†Œ 배열을 μ΄μš©ν•œ 풀이

ν¬μ†Œλ°°μ—΄μ„ ν•œμ€„λ‘œ μ„€λͺ…ν•˜λ©΄ '2^n 번 μ˜¬λΌκ°”μ„ λ•Œμ˜ λ…Έλ“œ μ°ΎκΈ°' 즉, μ–΄λ–€ λ…Έλ“œμ˜ 2^n번째 λΆ€λͺ¨μ°ΎκΈ°μΈ 것 κ°™μ•„μš”.

μ΅œμ†Œκ³΅ν†΅μ‘°μƒ & ν¬μ†Œ λ°°μ—΄ 2^n번째 λΆ€λͺ¨μ— λŒ€ν•œ 정보λ₯Ό dp 에 μ €μž₯해두고 μ“°λŠ” 것 κ°™λ„€μš”!

ν¬μ†Œ λ°°μ—΄ μ§±μ‹ κΈ°ν•˜λ„€,,,,,,,,,,,,,,,,,,,,μš”.........

Copy link
Member

@9kyo-hwang 9kyo-hwang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ν¬μ†Œ λ°°μ—΄ μ“°λŠ” λ°©λ²•μœΌλ‘œ ν•΄λ³Όλ €λ‹€κ°€, λ„μ €νžˆ 머리에 μ•ˆλ“€μ–΄μ™€μ„œ PR 보고 λ˜‘κ°™μ΄ λ‹€μ΅μŠ€νŠΈλΌ + 이진 νƒμƒ‰μœΌλ‘œ 츄라이...

from heapq import *
from collections import deque


def binary_search(paths: deque, energy: int) -> int:
    lo, hi = -1, len(paths)
    while lo + 1 < hi:
        mid = (lo + hi) // 2
        if paths[0][1] - paths[mid][1] <= energy:
            lo = mid
        else:
            hi = mid
            
    return 0 if lo == -1 else lo
    

def dijkstra(heap: list, distances: list, parents: list, tree: list):
    heappush(heap, (0, 1))
    distances[1] = 0
    
    while heap:
        du, u = heappop(heap)
        
        if distances[u] < du:
            continue
        
        for v, dv in tree[u]:
            if du + dv < distances[v]:
                distances[v] = du + dv
                parents[v] = u
                heappush(heap, (distances[v], v))


def main():
    input = open(0).readline
    
    n = int(input())
    energy_of_ants = [0] + [int(input()) for _ in range(n)]
    tree = [[] for _ in range(n + 1)]
    for _ in range(n - 1):
        a, b, c = map(int, input().split())
        tree[a].append((b, c))
        tree[b].append((a, c))
                
    
    heap = []
    distances = [10**9] * (n + 1)
    parents = [0] * (n + 1)
    
    dijkstra(heap, distances, parents, tree)

    answer = [0] * (n + 1)
    for i in range(2, n + 1):
        if len(tree[i]) > 1:
            continue
        
        node = i
        paths = deque()
        while node != 0:
            paths.append((node, distances[node]))
            node = parents[node]
        
        while paths:
            u, du = paths[0]
            if answer[u] != 0:
                paths.popleft()
                continue
            
            answer[u] = paths[binary_search(paths, energy_of_ants[u])][0]
            paths.popleft()
    
    print('\n'.join(map(str, answer[1:])))


if __name__ == "__main__":
    main()

Comment on lines +9 to +18
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neighbour 수λ₯Ό ꡳ이 기둝할 ν•„μš” 없이, graph_info의 크기가 κ³§ 이웃 λ…Έλ“œ 수λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

제 κ²½μš°μ—” listλ₯Ό μ¨μ„œ κ·Έλž˜ν”„(트리) 정보λ₯Ό κΈ°λ‘ν•©λ‹ˆλ‹€.

tree = [[] for _ in range(n + 1)]
for _ in range(n - 1):
    a, b, c = map(int, input().split())
    tree[a].append((b, c))
    tree[b].append((a, c))

이런 μ‹μœΌλ‘œ ν•˜λ©΄, λ°‘μ—μ„œ 리프 λ…Έλ“œλ₯Ό νŒλ³„ν•  λ•Œ

for i in range(2, n + 1):
    if len(tree[i]) > 1:
        continue
    ...

이런 μ‹μœΌλ‘œ i번째 λ…Έλ“œμ˜ 인접 리슀트 길이가 1인 κ²½μš°μ—λ§Œ ν™•μΈν•˜λŠ” μ‹μœΌλ‘œ 검사할 수 μžˆμŠ΅λ‹ˆλ‹€.

Comment on lines +35 to +38
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μœ„μ—μ„œ μ–ΈκΈ‰ν–ˆλ“―μ΄ 리프 λ…Έλ“œλ₯Ό νŒλ³„ν•˜λ©΄, 이 과정은 ν•„μš”μ—†μ–΄μ§‘λ‹ˆλ‹€. μ•„λž˜μ™€ 같이 λ°”λ‘œ κ²€μ‚¬ν•˜λ©΄ λ©λ‹ˆλ‹€ :)

answer = [0] * (n + 1)
for i in range(2, n + 1):
    if len(tree[i]) > 1:
        continue
    
    node = i
    paths = deque()
    while node != 0:
        paths.append((node, distances[node]))
        node = parents[node]
    
    while paths:
        ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tgyuuAn ν•œ μ€„λ‘œλŠ” μ†Œκ°œν•  수 μ—†λŠ” λ‚¨μž. 리뷰 μ™„λ£Œ βœ”οΈ

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants