λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

study money πŸ‘Ί

[λ°±μ€€] 2293번 : 동전1 ( 파이썬, μ‰¬μš΄ μ„€λͺ…, 코린이 버전 ) *이 λ¬Έμ œκ°€ λ„ˆλ¬΄ μ–΄λ €μ› λ˜ μ½”λ¦°μ΄λŠ” μ˜€μ„Έμš”*

 

λ””ν”Ό μžμ‹ ..... 풀어도 풀어도 μ–΄λ €μš΄ λ„ˆλž€ μœ ν˜• .... 자쑴감 λ–¨μ–΄λœ¨λ¦¬λŠ” μœ ν˜•

www.acmicpc.net/problem/2293

 

2293번: 동전 1

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

www.acmicpc.net

 

 λ””ν”Ό 문제λ₯Ό 많이 풀어보고 μžˆμ§€λ§Œ, 풀이λ₯Ό λ“€μ—ˆμ„ λ•ŒλŠ” μ†”μ§νžˆ 이해가 κ°‘λ‹ˆλ‹€. ν•˜μ§€λ§Œ, 아직 κΉŒμ§€λŠ” 슀슀둜 ν’€μ–΄λ³Ό λ•Œ, λ””ν”Όλ₯Ό μ μš©ν•˜λŠ” λ°μ—λŠ” 제 κ²½ν—˜μ΄ λ”Έλ¦¬λ‚˜ λ΄…λ‹ˆλ‹€. μ–΄μ©Œκ² μŠ΅λ‹ˆκΉŒ? λͺ»ν’€λ©΄ κ·Έ 풀이에 λŒ€ν•œ 해섀을 μ œλŒ€λ‘œ 읡히고, μ΄ν•΄ν•˜κ³ . λ‹€μŒμ— λͺ»ν’€μ–΄λ„, 또 κ²½ν—˜μ„ μŒ“λ‹€λ³΄λ©΄, λ””ν”Όλ₯Ό μ‘°κΈˆμ”© 더 잘 ν•  수 μžˆμ§€ μ•Šμ„κΉŒμš”?

 

 

μš°μ„  이 κ³Όλͺ©μ„ μˆ˜κ°•ν•˜κΈ° μ „ μ„  μˆ˜κ°• κ³Όλͺ©μž…λ‹ˆλ‹€. 이거 보면 이해가 ν™• κ°€λ”λΌκ΅¬μš”. 거기에 μ €λŠ” μ’€ 더 코린이 μ „μš©μœΌλ‘œ μˆŸκ°€λ½μ„ μ–ΉλŠ” 풀이λ₯Ό ν•  κ³„νšμ΄μ—μš”. μš°μ„  보고 μ˜€μ„Έμš© 

μ„ μˆ˜ κ³Όλͺ© * ν•„μˆ˜ μ‹œμ²­ * : 개인적으둜 λΈ”λ‘œκ·Έμ— λŒμ•„λ‹€λ‹ˆλŠ” λͺ¨λ“  풀이λ₯Ό λ΄€μ§€λ§Œ, 개인적으둜 μ΄κ²ƒλ§Œμ΄ μ €λ₯Ό ꡬ원해쀄 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. λ“€μ–΄λ³΄μ„Έμš”, μ˜μƒμœΌλ‘œ λ˜μ–΄μžˆμ–΄μ„œ 맀우 μ΄ν•΄ν•˜κΈ° νŽΈν–ˆμ–΄μš”.

https://youtu.be/2IkdAk1Loek

핡심 아이디어 μ„€λͺ… πŸ˜‡

 1원 λ‹¨μœ„λ§Œ 썼을 λ•Œ,

 1,2,3,4,5,6,7,8,9,10원을 λ§Œλ“€μ–΄λ΄…λ‹ˆλ‹€.

 κ²½μš°μ˜ μˆ˜κ°€ λͺ‡ 가지죠?

 

 λ‹€ ν•œ 가지죠?

 1원 λ‹¨μœ„λ§Œ μ¨μ„œ 1원 λ§Œλ“€λ €λ©΄ 1개, 2원 λ§Œλ“€λ €λ©΄ 2개, ... 10원 λ§Œλ“€λ €λ©΄ 10개 μ΄λ ‡κ²Œ, λͺ©ν‘œ ~원에 맞게 1원을 λ™μ›ν•˜λ©΄ λ©λ‹ˆλ‹€.

 

이제 2원 λ‹¨μœ„λ₯Ό ν•˜λ‚˜λ§Œ 더 동원해보죠. ( <- 이게 핡심. 점점 동전 λ‹¨μœ„λ₯Ό ν•˜λ‚˜μ”© 더 동원해 λ‚˜κ°€λŠ” κ±°μ—μš”. ) 단 !! μ΄λ•Œ 2원 λ‹¨μœ„λ₯Ό λ™μ›ν•œ κ²ƒμ΄λ―€λ‘œ, 1원 λ‹¨μœ„λ§Œ μ‚¬μš©λœ 경우의 μˆ˜λŠ” ν•΄λ‹Ήλ˜μ§€ μ•Šμ•„μš”. λͺ…μ‹¬ν•˜μ„Έμš”!! <- 이 포인트λ₯Ό μžŠμ§€ λ§ˆμ„Έμš”

 

두 번째 쀄을 λ³΄μ„Έμš”, 이제 1원 λ‹¨μœ„λ§Œ 가지고 λ§Œλ“  경우의 수 말고, "1원 (&& and μ•€λ“œ) 2원"을 동원할 λ•Œμ˜ 경우의 수λ₯Ό λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

μš°μ„  2μ›μœΌλ‘œ 1원을 λ§Œλ“€ μˆ˜λŠ” μ—†μ–΄μ„œ 0.

2원을 κΌ­ μ“΄λ‹€κ³  ν–ˆμ„ λ•Œ, 2원을 λ§Œλ“œλŠ” 경우의 μˆ˜λŠ” λͺ‡κ°œμ£ ? 2개 μ•„λ‹™λ‹ˆλ‹€. μ§‘μ€‘ν•˜μ„Έμš” !! 두 개라고 ν•˜μ‹  뢄은

1개죠. μ™œλƒν•˜λ©΄, 이제 1원과 2원을 λͺ¨λ‘ μ‚¬μš©ν•œ 경우의 수λ₯Ό κ³ λ €ν•˜κ³  있기 λ•Œλ¬Έμ΄μ—μš”. 

 

3원을 λ§Œλ“€λ €λ©΄μš”? 그럼? 

3원을 λ§Œλ“€λ €λ©΄ ν˜„μž¬μ˜ 경우, 2원을 무쑰건 μ¨μ•Όν•˜λ‹ˆκΉŒ, 2원을 무쑰건 μ“΄λ‹€κ³  치고, 그러면 μ‘°ν•©ν•΄λ‚΄μ•Όν•  돈이, 1μ›λ§Œ λ‚¨μžλ‚˜μš”? κ·Έμ΅Έ? 이제 이 1원을

방법1(1μ›λ§Œ μ“°κΈ°)κ³Ό

방법2(1원과 2원을 λͺ¨λ‘ μ“°κΈ°)둜 λ§Œλ“€ 수 μžˆλŠ” 경우의 수

λ“€μ˜ 합을 ꡬ해주면 λ©λ‹ˆλ‹€.

κ·Έλ ‡λ‹€κ³  ν•˜λ©΄, 방법1( 1μ›λ§ŒμœΌλ‘œ 1원을 λ§Œλ“œλŠ” 경우의 수 ) : 1가지

방법2( 1원 2원 λͺ¨λ‘ λ™μ›ν•œ 경우의 수 ) : 0가지

λ₯Ό λ”ν•΄μ„œ 써주면 λ©λ‹ˆλ‹€. 1이죠. κ·Έλž˜μ„œ λ°”λ‘œ μ € 2ν–‰ 3열에 1이 λ“€μ–΄κ°€λŠ” κ²λ‹ˆλ‹€.

 

이 μ›λ¦¬λ‘œ μ­‰μ­‰ μ±„μ›Œλ„£μ–΄λ΄μš” !!

그럼 1,2원 λͺ¨λ‘ λ™μ›ν•˜μ—¬ 4원을 λ§Œλ“€λ €λ©΄?

μš°μ„  무쑰건 2원을 μ¨μ•Όν•˜λ‹ˆκΉŒ 2원을 μ œν•˜μ—¬μ€λ‹ˆλ‹€. 그럼 4-2 => 2원을 방법1κ³Ό 방법2둜 λ§Œλ“€λ©΄ λ©λ‹ˆλ‹€.

μ—¬κΈ°μ„œ 1을 μ·¨ν•˜κ³ 
μ—¬κΈ°μ„œ 1을 μ·¨ν•œλ‹€.

그러면, 방법1κ³Ό 방법2λ₯Ό λ”ν•΄μ„œ, 2가지가 λ©λ‹ˆλ‹€.

κ·Έ κ²°κ³Όλ₯Ό μ¨μ£Όμ„Έμš”

 

κ²°λ‘  : νŒ¨ν„΄μ€ 무엇이닀? 예λ₯Ό λ“€μ–΄, 5원 λ‹¨μœ„λ₯Ό κΌ­ ν¬ν•¨ν•œμ±„λ‘œ, 1,2,5원 λ‹¨μœ„λ‘œ 10원을 λ§Œλ“€λ €λ©΄? μš°μ„  5원 λ‹¨μœ„λŠ” 무적ꢌ ν¬ν•¨μ΄λ‹ˆ λΉΌμ£Όκ³  μ‹œμž‘ν•œλ‹€. ( 그럼 1원 만으둜 5원 λ§Œλ“œλŠ” 방법1 / 1,2원 만으둜 5원 λ§Œλ“œλŠ” 방법2 / 1,2,5원 λͺ¨λ‘ μ¨μ„œ 5원 λ§Œλ“œλŠ” 방법3 ) <- 이 방법 μ„Έ 가지λ₯Ό λͺ¨λ‘ λ”ν•΄μ€€λ“œμ•„ !! μ΄κ±°μ˜€μŠ΅λ‹ˆλ‹€.

( λͺ©ν‘œ λ‹¨μœ„ - ν˜„μž¬ λ‹¨μœ„ ) μΈλ±μŠ€μ—μ„œμ˜ <- 이전 λ‹¨κ³„λ“€μ˜ λ””ν”Όκ°’ + ν˜„μž¬ 단계 λ””ν”Όκ°’

 

 

휴 ... 점화식이 λ“œλŽŒ μ™„μ„±λœ κ²ƒμž…λ‹ˆλ‹€. 이제 μ½”λ“œλ‘œ μ¨λ³΄μ„Έμš”. 이제 κ±°μ˜λ‹€ λ– μ„œ λ“œλ¦° κ²ƒμž…λ‹ˆλ‹€. μ½”λ“œλŠ” 밑에 μžˆμ–΄μš©.

numOfUnits, targetAmount = map( int, input().split() )
units = []
for _ in range(numOfUnits) :
    units.append( int( input() ))

# 두 가지 λ””ν”Ό 운영
    # prev_units_total
    # dp
prev_cases_total = [0] * targetAmount 
dp = [0] * targetAmount
firstUnit = units[0]

#
for idx in range( targetAmount ) : 
    if (idx+1) % firstUnit == 0 :
        prev_cases_total[idx] = 1
    else :
        prev_cases_total[idx] = 0

#
for unit in units[1:] :
    for idx in range(targetAmount) :
        if (idx+1) < unit :
            dp[idx] = 0
        elif (idx+1) == unit :
            dp[idx] = 1
        else :
            dp[idx] = dp[ ( idx - unit ) ] + prev_cases_total[ ( idx - unit ) ]
    #
    for k in range(targetAmount) :
        prev_cases_total[k] = dp[k] + prev_cases_total[k]
    

#
print(prev_cases_total[-1])