TIL 005 DP λŒ€ν‘œμœ ν˜•

μ‘°μ„±ν˜„Β·2021λ…„ 1μ›” 4일
0

μ •κΈ€

λͺ©λ‘ 보기
6/21

DPλŠ” μœ ν˜•μ„ 많이 μ ‘ν•˜λŠ”κ²Œ μ€‘μš”ν•˜λ‹€κ³  ν•œλ‹€.....πŸ˜‚

πŸ“• Knapsack

πŸ‘‰ μ ‘κ·Ό 방법

2차원 배열에 가방에 λ“€μ–΄κ°ˆ 수 μžˆλŠ” 무게λ₯Ό λŠ˜λ €κ°€λ©° λͺ¨λ“  경우의 수 비ꡐ.
물건을 가방에 넣을 수 μ—†λ‹€λ©΄, μ§€κΈˆκΉŒμ§€ 물건 쀑 μ΅œλŒ€ κ°€μΉ˜
넣을 수 μžˆλ‹€λ©΄, μ§€κΈˆ 물건의 κ°€μΉ˜ + μ „ ν–‰λ ¬μ—μ„œ μ§€κΈˆ 무게λ₯Ό 뺏을 λ•Œμ˜ κ°€μΉ˜

πŸ‘‰ μ½”λ“œ

def knapsack():
    dp = [[0 for _ in range(K+1)] for _ in range(N+1)]
    for i in range(1,N+1):
        for j in range(1,K+1):
            if A[i][0] > j:
                dp[i][j] = dp[i-1][j]
            else:
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-A[i][0]]+A[i][1])
    print(dp[-1][-1])

πŸ“• LCS

πŸ‘‰ μ ‘κ·Ό 방법

2차원 배열에 ν•œ 단어씩 λŠ˜λ €κ°€λ©° λͺ¨λ“  경우의 수λ₯Ό 비ꡐ.
μƒˆλ‘œ μž…λ ₯λ˜λŠ” 단어가 κ°™λ‹€λ©΄, μ „ λ°°μ—΄μ˜ +1
그렇지 μ•Šλ‹€λ©΄, μ§€κΈˆκΉŒμ§€ λ§Œλ“  단어 쀑 μ΅œλŒ€

πŸ‘‰ μ½”λ“œ

def max_lcs():
	N = len(s1)
	M = len(s2)

	lcs = [[0 for _ in range(M+1)] for _ in range(N+1)]

	for i in range(1,N+1):
		for j in range(1,M+1):
			if s1[i-1] == s2[j-1]:
				lcs[i][j] = lcs[i-1][j-1] + 1
			else:
				lcs[i][j] = max(lcs[i-1][j],lcs[i][j-1])
	print(lcs[-1][-1])

πŸ“• ν–‰λ ¬κ³±μ…ˆμˆœμ„œ

πŸ‘‰ μ ‘κ·Ό 방법

λͺ¨λ“  ν–‰λ ¬κ³±μ…ˆμ˜ 경우의 수λ₯Ό κ³±ν•΄μ€€λ‹€.
μ–‘ 끝은 κ³ μ •μ΄λ‚˜ 쀑간을 μ–΄λ–»κ²Œ μͺΌκ°œλŠλƒλ‘œ 경우의 μˆ˜κ°€ λ‚˜λ‰˜λŠ” 것을 μ΄μš©ν•œλ‹€.
A,B,C,D,E,F λ₯Ό 예둜 λ“€λ©΄,
(A)(B,C,D,E,F)
(A,B) (C,D,E,F)
(A,B,C)(D,E,F)
(A,B,C,D)(E,F)
(A,B,C,D,E)(F)
κ°€ λͺ¨λ“  경우의 수 일 것인닀. λ‹€λ§Œ 묢인 μ—°μ‚°μ˜ μ΅œμ†Œκ°’μ€ 이미 ꡬ해져 μžˆμ–΄μ•Ό ν•  것이닀.
2차원 λ°°μ—΄μ—μ„œ κ³„μ‚°λ˜λŠ” μˆœμ„œμ™€ λͺ¨μ–‘을 보면 λͺ¨λ“ μ˜ 경우의 μˆ˜κ°€ 고렀되고 μžˆμŒμ„ 쒀더 μ§κ΄€μ μœΌλ‘œ λ³Ό 수 μžˆλ‹€.
주석과 점화식을 잘보자

πŸ‘‰ μ½”λ“œ

dp = [[0 for _ in range(N)] for _ in range(N)]
for d in range(1,N): # μ–Όλ§ˆλ§ŒνΌμ˜ 크기둜 μͺΌκ°€ 것인가
    for i in range(N-d): # μ‹œμž‘μ 
        j = i+d # 끝점
        dp[i][j] = math.inf
        for k in range(i,i+d): # λ‚˜λˆ„λŠ” 점
            dp[i][j] = min(dp[i][j], dp[i][k]+dp[k+1][j]+A[i][0]*A[k][1]*A[j][1])
print(dp[0][N-1])

πŸ“• TSP(μ™ΈνŒμ›μˆœν™˜)

πŸ‘‰ μ ‘κ·Ό 방법

DFS처럼 μž¬κ·€λ‘œ 완전탐색해 μ΅œμ†Œκ°’μ„ μ·¨ν•œλ‹€.
μž¬κ·€ 쀑에 ꡬ체적인 κ²½λ‘œλŠ” μ€‘μš”ν•˜μ§€ μ•ŠμŒμœΌλ‘œ λΉ„νŠΈ 연산을 μ‚¬μš©
μ€‘λ³΅λ˜μ§€ μ•Šλ„λ‘ μž¬λ°©λ¬Έμ„ λ§‰λŠ”λ‹€
https://developmentdiary.tistory.com/406
https://shoark7.github.io/programming/algorithm/solve-tsp-with-dynamic-programming

πŸ‘‰ μ½”λ“œ

dp = [[None]*(1<<N) for _ in range(N)]

def find_path(last,visited):
    if visited == (1<<N)-1 # λͺ¨λ‘ λ°©λ¬Έ μ‹œ
        return dp[last][0] or math.inf # 0μΌλ•ŒλŠ” math.inf
    if dp[last][visited] is not None: # 쀑볡 λ°©λ¬Έ μ‹œ
        return dp[last][visited]
    tmp = math.inf
    for i in range(N):
        # λ°©λ¬Έν•œμ μ΄ μ—†κ³  갈 수 μžˆλ‹€λ©΄ κ·Έ 쀑 μ΅œμ†Œκ°’
        if visited & (1<<i) == 0 and A[last][i] != 0:
            tmp = min(tmp,find_path(i,visited | (1<<i)) + A[last][[i])
    dp[last][visted] = tmp
    return tmp
    

πŸ“• κ³„λ‹¨μ˜€λ₯΄κΈ°

πŸ‘‰ μ ‘κ·Ό 방법

2차원 배열을 이용. μ„Έ 칸을 μ—°μ†ν•΄μ„œ 점프할 수 μ—†λ‹€. 즉, ν•œμΉΈ λ›°μ—ˆλ‹€λ©΄ λ‹€μŒλ²ˆμ—λŠ” 두 칸을 λ›°μ–΄μ•Όν•œλ‹€.
κ·Έλž˜μ„œ N에 λŒ€ν•΄ 두 개의 배열을 μ¨μ„œ A[N][0]은 두 μΉΈ λ›΄ κ°’ A[N][1]은 ν•œ μΉΈ λ›΄ 값을 λ„£μ–΄μ€€λ‹€.

πŸ‘‰ μ½”λ“œ

dp = [[0,0] for _ in range(N)]
dp[0] = [A[0],0] # μ΄ˆκΈ°κ°’μ€ λ„£μ–΄μ€˜μ•Ό 
dp[1] = [A[1],A[1]+A[0]]
for i in range(2,N):
    dp[i][0] = max(dp[i-2][0],dp[i-2][1]) + A[i]
    dp[i][1] = dp[i-1][0] + A[i]
    
print(max(dp[N-1][0],dp[N-1][1]))
    

πŸ“• RGB

πŸ‘‰ μ ‘κ·Ό 방법

Nx3배열에 집씩 λŠ˜λ €κ°€λ©° λͺ¨λ“  경우의 수λ₯Ό 비ꡐ.
전에 μ‚¬μš©λœ 색깔을 λΊ€ λ‚˜λ¨Έμ§€ 두 개의 색에 λŒ€ν•΄ μ΅œμ†Ÿκ°’μ„ μ—°μ‚°

πŸ‘‰ μ½”λ“œ

dp = [[0,0,0] for _ in range(N)]
dp[0] = [A[0][0],A[0][1],A[0][2]]
for i in range(1,N):
	dp[i][0] = min(dp[i-1][1]+A[i][0],dp[i-1][2]+A[i][0])
	dp[i][1] = min(dp[i-1][0]+A[i][1],dp[i-1][2]+A[i][1])
	dp[i][2] = min(dp[i-1][0]+A[i][2],dp[i-1][1]+A[i][2])
print(min(dp[N-1][0],dp[N-1][1],dp[N-1][2]))

πŸ“• 연속합

πŸ‘‰ μ ‘κ·Ό 방법

정말 κ°„λ‹¨ν•œ λ¬Έμ œμ˜€λŠ”λ° ν•œμ°Έ κ³ λ―Όν•œ 문제.
1차원 dp 에 μŒμˆ˜κ°€ μ•„λ‹Œ 연속 μˆ˜λ“€λ§Œ λͺ¨λ‘ 더함.

πŸ‘‰ μ½”λ“œ

dp = [0 for _ in range(N)]
for i in range(0,N):
	dp[i]= max(0,dp[i-1])+A[i]
print(max(dp))

πŸ“• 2xn 타일

πŸ‘‰ μ ‘κ·Ό 방법

ν”Όλ³΄λ‚˜μΉ˜ μˆ˜μ—΄λ‘œ ν’€λ¦¬λŠ” λ¬Έμ œκ°€ κ½€ μžˆλ‹€.

πŸ‘‰ μ½”λ“œ

dp = [0 for _ in range(N)]
dp[0], dp[1] = 1,2
for i in range(2,N):
    dp[i] = (dp[i-1] + dp[i-2])
print(dp[N-1])

πŸ“• 동전1

πŸ‘‰ μ ‘κ·Ό 방법

knapsack 처럼 λ™μ „μ˜ λͺ¨λ“  λ™μ „μ˜ κ°€μΉ˜μ— λŒ€ν•΄ 동전이 λ§Œλ“€ 수 μžˆλŠ” dp λ₯Ό λ§Œλ“ λ‹€.
잘 보면 N μ‚¬μ΄μ¦ˆμ˜ dp만으둜 ν•΄κ²° κ°€λŠ₯ν•˜λ‹€.

πŸ‘‰ μ½”λ“œ

dp = [0 for _ in range(K+1)]
dp[0] = 1
for i in range(0,N):
	for j in range(1,K+1):
		if j >= A[i]:
			dp[j] = dp[j-A[i]] + dp[j]
print(dp[K])
profile
JazzingπŸ‘¨β€πŸ’»

0개의 λŒ“κΈ€