백준풀이-python

1005 ACM Craft

Fug 2021. 8. 9. 16:23

https://www.acmicpc.net/problem/1005

#dp

 

1005번: ACM Craft

첫째 줄에는 테스트케이스의 개수 T가 주어진다. 각 테스트 케이스는 다음과 같이 주어진다. 첫째 줄에 건물의 개수 N 과 건물간의 건설순서규칙의 총 개수 K이 주어진다. (건물의 번호는 1번부

www.acmicpc.net

#dp

 

오늘 배운건 dp는 각 인덱스가 바뀌지 않는 다는 가정하에 움직인다는 것이다. 고로 지나간 dp의 인덱스는 다시 확인 할

 

필요가 없다. 과거의 과정에서 이미 확인되어서 나온것이다. 이 문제에서도 똑같이 나왔다. 위상정렬로 되어있지만 사실

 

왜 위상정렬로 분류 되어있는가는 잘 모르겠다. 스택을 사용하면 오히려 어렵다는 생각이 들었다. 재귀와 dp를 이용하여

 

코드를 짜보니 깔끔하게 나왔다. 오늘 새로 배운 __name__=="__main__": 와 setrecursionlimit 그리고 :,->,등등 주석들은

 

포스팅을 따로 올릴 것이다. 이번 문제도 사실 답지를 조금 봤다. 새로 아는 것들도 많았고 tistory에 있는 대중적인 문제

 

가 아니여서 일단 성공시켜놓고 코드 쉐도잉을 하여 습득해야겠다는 판단 하에 있었고 덕분에 많은 것을 배운것 같다.

 

#코드

import sys

#setrecursionlimit 과 stdin을 사용하기 위한 sys import

from collections import defaultdict

#defaultdict를 사용하지 않고 이중리스트 해도 되는데 이게 더 편해졌다

input=sys.stdin.readline

#스탠다드 인풋

t :"test case"

n:"the number of buildings"

k:"the number of construction order rules"

d:"time"

#주석 처리 t , n, k, d 를 주석처리 하여 나타내줌 코드에는 포함되지않고 #이거라고 생각하면 편할것 같다.

def get_times(i:int) -> int:

#함수에서도 역시 ->을 이용하면 주석으로 달수 있다. 암튼 이 함수는 dp를 이용하여 max값을 구하는 함수

if dp[i]!=-1:
return dp[i]

#dp가 초기값이 아니면 지나간 dp이기때문에 바로 리턴한다.

result=0

for build in order[i]:

result=max(result,get_times(build))

#어떻게 보면 벨만포드인것 같기도

dp[i]=result+d[i]

return dp[i]

#최대값을 d[i]와 나눈후 리턴 이것의 최종값은 답이 될것이다.

def main() -> None:

#주석으로 ->이걸로 return 값은 None인걸 나타내준다.

global dp,order,d

#dp,order,d을 global화 하지않으면 함수에 다 끼워서 돌려야된다. 귀찮으니깐 전역함수화 시키자.

for t in range(int(input())):

n,k=map(int,input().split())

#n,k 건물의 개수, 건설순서규칙 개수

d=[0]+list(map(int,input().split()))

#시간

order=defaultdict(list)

for i in range(k):

u,v=map(int,input().split())

order[v].append(u)

#건설 순서 규칙 order

dp=[-1 for i in range(n+1)]

#dp -1로 시작하자 0으로 시작해도 되긴한데

print(get_times(int(input())))

#get_times로 변한 dp에서 목표값을 인덱스로 갖는걸 출력해라 하하하하

if __name__ == "__main__":
sys.setrecursionlimit(2000)

#재귀함수의 한계값을 늘린다.

main()

 

#어렵고 어렵고 어렵다. 하지만 얻은게 많은 문제