🧩 Problem Solving/[λ°±μ€€]

[λ°±μ€€] 2293 동전 1 (python 파이썬)

μ œλ΄‰μ•„ 2022. 7. 5. 02:34

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

 

2293번: 동전 1

첫째 쀄에 n, kκ°€ μ£Όμ–΄μ§„λ‹€. (1 ≤ n ≤ 100, 1 ≤ k ≤ 10,000) λ‹€μŒ n개의 μ€„μ—λŠ” 각각의 λ™μ „μ˜ κ°€μΉ˜κ°€ μ£Όμ–΄μ§„λ‹€. λ™μ „μ˜ κ°€μΉ˜λŠ” 100,000보닀 μž‘κ±°λ‚˜ 같은 μžμ—°μˆ˜μ΄λ‹€.

www.acmicpc.net

DP λ„ˆλ¬΄ μ–΄λ ΅λ‹€μ—μš”


아이디어

1. DP

  • 문제λ₯Ό 보고 dp문제인 것도 μ•Œκ³  'DP [k] = 합이 kκ°€ λ˜λŠ” 경우의 수'λΌλŠ” 것도 μ•Œμ•˜λ‹€.
  • 근데 점화식 아이디어가 λ– μ˜€λ₯΄μ§€ μ•Šμ•„ κ²€μƒ‰μ˜ νž˜μ„ λΉŒλ Έλ‹€.
  • 일주일 뒀에 또 ν’€μ–΄λ΄€λŠ”λ° 또 κΉŒλ¨Ήμ—ˆλ‹€. 이해λ₯Ό λͺ» ν–ˆλ‹€λŠ” λœ»μ΄λ‹€.
  • 이번 κΈ°νšŒμ— μ œλŒ€λ‘œ μ΄ν•΄ν•˜κ³  λ„˜μ–΄κ°€κΈ°λ‘œ 함.

μ½”λ“œ μ„€λͺ…

DP = [0] * (k + 1)
DP[0] = 1
for c in coins:
    for i in range(c, k + 1):
        DP[i] += DP[i - c]

일단 μ½”λ“œλŠ” 정말 κ°„λ‹¨ν•˜λ‹€. ν•˜λ‚˜ν•˜λ‚˜ λœ―μ–΄λ³΄λ„λ‘ ν•˜μž.

 

λ¨Όμ € λ¬Έμ œμ—μ„œ "μ‚¬μš©ν•œ λ™μ „μ˜ ꡬ성이 같은데, μˆœμ„œλ§Œ λ‹€λ₯Έ 것은 같은 κ²½μš°μ΄λ‹€."λΌλŠ” 말은

예λ₯Ό λ“€μ–΄ 합이 4κ°€ λ˜λŠ” κ²½μš°μ—μ„œ '1 1 2'와 '2 1 1', '1 2 1'은 같은 경우둜 μ·¨κΈ‰ν•œλ‹€λŠ” λœ»μ΄λ‹€.

이걸 κ³ λ € μ•ˆ ν•˜λ©΄ μ–΄λ–€ κ²½μš°κ°€ μƒκΈ°λŠ”μ§€ λ‹€μŒ μ˜ˆμ‹œλ₯Ό 보면 λœλ‹€. μ•Œλ©΄ κ·Έλƒ₯ λ„˜μ–΄κ°€λ„ 됨.

 

 


자 예λ₯Ό λ“€μ–΄μ„œ 동전 μ’…λ₯˜κ°€ '1, 2'κ°€ 있고 k = 4, 합이 4κ°€ λ˜λŠ” 경우의 수λ₯Ό κ΅¬ν•œλ‹€κ³  μƒκ°ν•΄λ³΄μž.

그럼 일단 κ²°κ³Όλ₯Ό λ¨Όμ € 생각해보면 dp [4]에 3이 μ €μž₯λ˜μ•Όν•œλ‹€.

직접 경우λ₯Ό 적어보면 '1 1 1 1', '1 1 2', '2 2'둜 3κ°€μ§€κ°€ λ‚˜μ™€μ•Ό 함.

 

그럼 λ‚΄κ°€ μ§€κΈˆ 1원이 μžˆλ‹€κ³  μƒκ°ν•˜μž. μ—¬κΈ°μ„œ λ‚˜λŠ” 3원을 μΆ”κ°€ν•΄ μ£Όλ©΄ 4원이 λœλ‹€.이 말은 3원을 λ§Œλ“œλŠ” κ²½μš°μ—μ„œ 1μ›λ§Œ μΆ”κ°€ν•΄μ£Όλ©΄ 4원이 λœλ‹€λŠ” μ†Œλ¦¬λ‹€.μ–΄ 그럼 3원을 λ§Œλ“œλŠ” κ²½μš°λŠ” 뭐가 μžˆμ§€λΌκ³  생각해보면 '1 1 1', '1 2'κ°€ μžˆλ‹€. μ—¬κΈ°μ„œ 1원을 λ”ν•˜λ©΄ '1 1 1 1', '1 2 1' 두 κ°€μ§€ κ²½μš°κ°€ λ‚˜μ˜¨λ‹€.μ΄λ ‡κ²Œ 되면 μœ„μ—μ„œ λ§ν•œ 같은 경우둜 μ·¨κΈ‰ λ¬Έμ œκ°€ 생긴닀. 

 

이게 무슨 μ†Œλ¦¬λƒ. μ΄λ²ˆμ—λŠ” 2원이 μžˆλ‹€κ³  μƒκ°ν•˜μž. 여기에 2원을 μΆ”κ°€ν•΄μ£Όλ©΄ 4원이 λœλ‹€.2원을 λ§Œλ“œλŠ” κ²½μš°λŠ” '1 1', '2' 두 κ°€μ§€κ°€ μžˆλ‹€.여기에 2원을 λ”ν•˜λ©΄'1 1 2', '2 2' 두 κ°€μ§€κ°€ λœλ‹€.

 

정닡은 3인데 μœ„μ™€ 같은 λ°©μ‹μœΌλ‘œ ν•˜λ‹ˆ 경우의 μˆ˜κ°€ 4κ°€ λœλ‹€.

'1 1 2'와 '1 2 1'을 λ‹€λ₯Έ 경우둜 μ·¨κΈ‰ν•΄μ„œ 생긴 λ¬Έμ œλ‹€.

 

그럼 μ–΄λ–»κ²Œ ν•΄μ•Ό ν•˜λ‚˜. 동전을 ν•˜λ‚˜μ”© λ„£λŠ”λ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€.

동전을 μ‚¬μš©ν•˜λŠ” κ°€μ§€ 수λ₯Ό λŠ˜λ €κ°€λ©° dp값을 μ—…λ°μ΄νŠΈν•œλ‹€λŠ” λœ»μ΄λ‹€. 

 

ν‘œλ‘œ λ‚˜νƒ€λ‚΄λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

DP 0 1 2 3 4
c = 1μΌλ•Œ 1 1 (1 1) 1 (1 1 1) 1 (1 1 1 1)
c = 2μΌλ•Œ 1 1 2 (1 1, 2) 2 (1 1 1, 1 2) 3 (1 1 1 1, 1 1 2, 2 2)

 

μ΄λ ‡κ²Œ ν•˜λ©΄ '1 2'에 1원을 μΆ”κ°€ν•΄μ„œ 4λ₯Ό λ§Œλ“œλŠ” κ²½μš°λŠ” μžλ™μœΌλ‘œ μ œμ™Έλœλ‹€.

μ™œλƒ 이미 '1 2'λΌλŠ” 것은 1원을 μ“°κ³  2원을 μΌλ‹€λŠ” 건데, μ—¬κΈ°μ„œ λ‹€μ‹œ 1원을 μ“Έ 수 μ—†λ‹€!

μ‹€μ œ for문으둜 생각해보면 c = 1일 λ•Œκ°€ μ§€λ‚˜κ°€κ³  c = 2일 λ•Œ λ‹€μ‹œ c = 1일 λ•Œλ‘œ λŒμ•„κ°ˆ 수 μ—†λ‹€λŠ” 말이닀.

 

λ‚΄κ°€ 이 μ–˜κΈ°λ₯Ό 길게 ν•œ μ΄μœ λŠ” μΈν„°λ„·μ—μ„œ μ½”λ“œλ₯Ό μ°Ύμ•„λ³Ό λ•Œ '이쀑 for문을 μ“°λŠ” 것은 μ•Œκ² λŠ”λ° μ™œ coin리슀트 for문이 λ¨Όμ €μ§€?'에 λŒ€ν•œ μ˜λ¬Έμ„ 해결을 μœ„ν•¨μ΄μ—ˆλ‹€.

 

λ”°λΌμ„œ

DP [4] (1,2 μ›μœΌλ‘œ 4λ₯Ό λ§Œλ“œλŠ” 경우의 수) = DP[4] (μ›λž˜ 1μ›μœΌλ‘œλ§Œ 4λ₯Ό λ§Œλ“œλŠ” 경우의 수) + DP[4 - 2] (1, 2 μ›μœΌλ‘œ 2λ₯Ό λ§Œλ“œλŠ” 경우의 수, μ—¬κΈ°μ„œ 2μ›λ§Œ μΆ”κ°€ν•΄μ£Όλ©΄ 4κ°€ λ˜λ‹ˆκΉŒ.)

-> DP[i] += DP[i - c] 둜 ν‘œν˜„ν•  수 μžˆλ‹€.

 

μ—¬κΈ°μ„œ i - cκ°€ μŒμˆ˜κ°€ 되면 μ•ˆ λ˜λ‹ˆκΉŒ iλŠ” cλΆ€ν„° μ‹œμž‘ν•˜κ²Œ μž‘μ„±ν•΄μ•Ό ν•œλ‹€.

2μ›μœΌλ‘œ 1원을 λͺ»λ§Œλ“œλŠ” 것과 같은 말이닀.

 

μ΄λ ‡κ²Œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ DP [0]의 값이 ν•„μš”ν•˜λ‹€.

DP [0]μ΄λΌλŠ” 것은 DP [k - k]라고 μƒκ°ν•˜λ©΄ 쉽닀.

λ‚΄κ°€ 합이 kκ°€ 되게 λ§Œλ“€ λ•Œ, kμ›μ§œλ¦¬ 동전 ν•˜λ‚˜λ§Œ μ“°λŠ” κ²½μš°λ‹€.

κ·Έλž˜μ„œ μ΄ˆκΈ°μ— DP[0] = 1을 μ €μž₯ν•œλ‹€. 

 

 

이차원 배열을 μ“°λ©΄ μ’€ 더 μ§κ΄€μ μœΌλ‘œ μ•Œμ•„λ³Ό 수 μžˆμ§€λ§Œ, λ©”λͺ¨λ¦¬ μ œν•œμ΄ μžˆμ–΄μ„œ 값듀을 μ—…λ°μ΄νŠΈν•΄μ£ΌλŠ” 방식을 택해야 ν•œλ‹€.


전체 μ½”λ“œ

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

coins = []
for i in range(n):
    coins.append(int(input()))
coins.sort()

DP = [0] * (k + 1)
DP[0] = 1
for c in coins:
    for i in range(c, k + 1):
        DP[i] += DP[i - c]
print(DP[k])