크래프톤 정글 TIL : 0918

lazyArtisan·2024년 9월 18일
0

정글 TIL

목록 보기
80/147

⚔️ 백준


📌 1005 ACM Craft

while now_building:
    build = heapq.heappop(now_building)
    B_t, B = build[0], build[1]
    total_time += B_t
    if B == win:
        break
    Qsize = len(now_building)
    next_building(B,now_building,build_order,indegree)
    # 다른 건물들도 동시에 지을 수 있기 때문에 고려
    for i in range(Qsize):
        now_building[i][0] -= B_t
        if now_building[i][0]==0:
            next_building(build[1],now_building,build_order,indegree)

heappush로 들어가버리면 이전에 짓고 있던 건물들과 섞여버림

sub_Q 라는 유예용 큐 선언해서 해결

import sys
input=sys.stdin.readline
from collections import deque
import heapq

# 다 지었으면 다음 건물 indegree 지워주고 
# 다음 건물을 지을까말까 확인하는 과정
def next_building(B,build_order,indegree,sub_Q):
    for next in build_order[B]:
        indegree[next]-=1
        if indegree[next] == 0:
            sub_Q.append(next)

T=int(input())
for _ in range(T):
    # 각 경기에 대한 정보 받아오기
    total_time=0
    N,K=map(int,input().split()) # N: 건물개수, K: 건물순서규칙개수
    build_time=[0]+list(map(int,input().split()))
    build_order={i:[] for i in range(N+1)}
    indegree=[0 for _ in range(N+1)]
    for _ in range(K):
        X,Y=map(int,input().split())
        build_order[X].append(Y) # X를 지은 후에 Y를 지을 수 있음
        indegree[Y]+=1
    win=int(input())
    # indegree가 0이 되면 건설시킬 수 있음
    # indegree가 0이 된 놈들은 전부 큐에 넣는다
    # 하나씩 넣을 때마다 다음에 지날 시간과 비교하여 
    # 더 낮으면 지날 시간을 변경한다

    # 처음 지을 건물들 우선순위 큐에 넣기
    now_building=[]
    for i in range(1,N+1):
        if indegree[i]==0:
            heapq.heappush(now_building,[build_time[i],i])
    # 짓기 시작
    while now_building:
        sub_Q=deque()
        build = heapq.heappop(now_building)
        B_t, B = build[0], build[1]
        total_time += B_t
        if B == win:
            break
        Qsize = len(now_building)
        next_building(B,build_order,indegree,sub_Q)
        # 다른 건물들도 동시에 지을 수 있기 때문에 고려
        for i in range(Qsize):
            now_building[i][0] -= B_t
            if now_building[i][0]==0:
                next_building(build[1],build_order,indegree,sub_Q)
        # 순서가 섞이니까 유예를 둔 뒤에 추가하기
        for b in sub_Q:
            heapq.heappush(now_building,[build_time[b],b])
    print(total_time

좀 길긴 하지만 일단 풀었는데 50몇퍼에서 틀렸습니다 뜸

# 다른 건물들도 동시에 지을 수 있기 때문에 고려
    for i in range(Qsize):
        now_building[i][0] -= B_t
        if now_building[i][0]==0:
            next_building(now_building[i][1],build_order,indegree,sub_Q)

찬찬히 봤더니 now_building[i][1] 이 부분이 build[1]로 되어있었다. 아니 그럼 예제는 어떻게 맞은거고 50%까진 어떻게 올라간거지;

예제랑 50퍼까지는 해당 정점과 무조건 이어졌는데 50퍼 이상부터는 해당 정점과 연결 안돼있는 것들도 indegree가 0이 되는듯.

import sys
input=sys.stdin.readline
from collections import deque
import heapq

# 다 지었으면 다음 건물 indegree 지워주고 
# 다음 건물을 지을까말까 확인하는 과정
def next_building(B,build_order,indegree,sub_Q):
    for next in build_order[B]:
        indegree[next]-=1
        if indegree[next] == 0:
            sub_Q.append(next)

T=int(input())
for _ in range(T):
    # 각 경기에 대한 정보 받아오기
    total_time=0
    N,K=map(int,input().split()) # N: 건물개수, K: 건물순서규칙개수
    build_time=[0]+list(map(int,input().split()))
    build_order={i:[] for i in range(N+1)}
    indegree=[0 for _ in range(N+1)]
    for _ in range(K):
        X,Y=map(int,input().split())
        build_order[X].append(Y) # X를 지은 후에 Y를 지을 수 있음
        indegree[Y]+=1
    win=int(input())

    # 처음 지을 건물들 우선순위 큐에 넣기
    now_building=[]
    for i in range(1,N+1):
        if indegree[i]==0:
            heapq.heappush(now_building,[build_time[i],i])
    # 짓기 시작
    while now_building:
        sub_Q=deque()
        build = heapq.heappop(now_building)
        B_t, B = build[0], build[1]
        total_time += B_t
        if B == win:
            break
        if B_t == 0:
            continue
        Qsize = len(now_building)
        next_building(B,build_order,indegree,sub_Q)
        # 다른 건물들도 동시에 지을 수 있기 때문에 고려
        for i in range(Qsize):
            now_building[i][0] -= B_t
            if now_building[i][0]==0:
                next_building(now_building[i][1],build_order,indegree,sub_Q)
        # 순서가 섞이니까 유예를 둔 뒤에 추가하기
        for b in sub_Q:
            heapq.heappush(now_building,[build_time[b],b])
    print(total_time)
                
# now_building[i][0] 부분에 build 써버림
# win을 만들면 종료되게 하는거 깜빡함 - 결과가 말해주니까 알았지만
# heappush로 들어가버리면 이전에 짓고 있던 건물들과 섞여버림

일단 맞았습니다는 떴음

if B_t == 0:
    continue

이거 삭제하니까 또 틀렸습니다 떴음

import sys

sys.setrecursionlimit(1000000)

def ACMcraft(n):
    if not graph[n]:
        return time[n]
    
    if dp[n] == -1:
    
        for bef in graph[n]:
            dp[n] = max(dp[n], ACMcraft(bef) + time[n])
    
    return dp[n]

input = sys.stdin.readline

T = int(input())
for _ in range(T):#재귀dp돌릴거임
    N, K = map(int, input().split())
    time = [-1] + list(map(int, input().split()))
    dp = [-1] * (N+1)
    graph = [[] for _ in range(N+1)] #선행과정 가리킴

    for _ in range(K):
        x, y = map(int, input().split())
        graph[y].append(x)
    W = int(input())

    print(ACMcraft(W))

https://www.acmicpc.net/source/83904073

아니 dp로 풀면 복잡하게 수식 죽 쓸 필요도 없네;
심지어 빠름.

import sys
from collections import deque
input = sys.stdin.readline
test = int(input())
time = []
ans = [0]*(test)
for t in range(test):
    n,k = map(int,input().split())
    time = [0] + list(map(int, input().split()))
    result = [0] * (n+1)
    adjacent = [[] for _ in range(n+1)]
    indegree = [0] * (n+1)
    for i in range(k):
        a,b = map(int,input().split())
        adjacent[a].append(b)
        indegree[b] += 1
    x = int(input())

    #위상정렬 start
    queue = deque()
    for i in range(1,n+1):
        if indegree[i] == 0:
            queue.append(i)
            result[i] = time[i]
    while queue:
        node = queue.popleft()
        if node == x:
            break
        for c in adjacent[node]:
            result[c] = max(result[c],result[node] + time[c])
            if indegree[c] == 1:
                queue.append(c)
            indegree[c] -= 1
    ans[t] = result[x]
    #위상정렬 end

for t in range(test):
    print(ans[t])

https://www.acmicpc.net/source/83651286

max() 함수를 쓰는게 키포인트인 것 같음.

https://cobokjang.tistory.com/23
https://woojeenow.tistory.com/entry/%EB%B0%B1%EC%A4%80-1005-ACM-Craft-c
https://blog.itcode.dev/posts/2021/06/01/a1005

'자신에게 필요한 선행 건물 중 최대 시간을 가진 건물 + 자기 자신에 걸리는 시간'이 자신이 만들어지는 최소 시간이다.

위상 정렬할 때 굳이 indegree가 0이거나 특정 조건(여기선 시간)이 충족돼야만 정보를 기록하는게 아니라 죄다 기록해버리고 최댓값만 남기는 식으로 하면 간단해지는듯

그리고 그게 dp라고 할 수 있고

위에 있는 간단한 재귀 코드는

만들어야할 건물로부터 역탐색을 했다.
'자신에게 필요한 선행 건물 중 최대 시간을 가진 건물 + 자기 자신에 걸리는 시간'을 재귀로 역탐색해서 if not graph[n]일 때 (indegree가 0인 기초 건물들) 종료 조건 걸어놓고, 이전 건물들의 시간을 전부 구했다면 해당 건물을 건축하는데까지 걸린 시간을 반환하는 식으로 코드 짬.

짠 사람 대단하긴 한데 흡수 할 수는 있을지도
알고 체화시키면 별거아닐듯
체화시키는게 문제지

그리고 임계경로 답지 보면서 왜 틀렸는지 확인하려고 했는데
이 문제가 임계경로랑 똑같아서
안 보고 직접 똑같이 재귀로 풀어보면 될듯

0개의 댓글