Potato
์•ˆ๋…•ํ•˜์„ธ์š”, ๊ฐ์žก๋‹ˆ๋‹ค?๐Ÿฅ” ^___^ ๐Ÿ˜บ github ๋ฐ”๋กœ๊ฐ€๊ธฐ ๐Ÿ‘‰๐Ÿป

Algorithm/Basic

[์•Œ๊ณ ๋ฆฌ์ฆ˜] Dynamic Programming (๋™์  ๊ณ„ํš๋ฒ•, DP) (feat. Swift ์Šค์œ„ํ”„ํŠธ)

๊ฐ์ž ๐Ÿฅ” 2022. 3. 3. 17:46
๋ฐ˜์‘ํ˜•

 

Dynamic Programming (๋™์  ๊ณ„ํš๋ฒ•)

๋™์ ๊ณ„ํš๋ฒ•(๋‹ค์ด๋‚˜๋ฏน ํ”„๋กœ๊ทธ๋ž˜๋ฐ) ์ด๋ž€, ๋ณต์žกํ•œ ๋ฌธ์ œ๋ฅผ ๊ฐ„๋‹จํ•œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„์–ด ํ‘ธ๋Š” ๋ฐฉ๋ฒ•์„ ๋งํ•œ๋‹ค. ์ด๊ฒƒ์€ ๋ถ€๋ถ„ ๋ฌธ์ œ ๋ฐ˜๋ณต๊ณผ ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์— ๋น„ํ•ด ๋”์šฑ ์ ์€ ์‹œ๊ฐ„์„ ๋‚ด์–ด ํ’€ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. - Wikipedia

โ–ท ์ฝ”๋”ฉํ…Œ์ŠคํŠธ์—์„œ์˜ DP

์ฝ”๋”ฉํ…Œ์ŠคํŠธ์˜ ๋‹จ๊ณจ ๋ฌธ์ œ๋กœ ์ถœ์ œ๋˜๊ณ  ์žˆ๊ธฐ์— ํ•„์ˆ˜์ ์œผ๋กœ ์•Œ์•„์•ผํ•˜๋Š” ๊ฐœ๋… ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๊ฐ„ํ˜น ์ œ์•ฝ์‚ฌํ•ญ์— ์ฃผ์–ด์ง€๋Š” ์ˆซ์ž์˜ ๋ฒ”์œ„๊ฐ€ ํฌ๊ณ , ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ์—„์ฒญ ๋งŽ์€ ๋ฌธ์ œ๋“ค์ด ๋Œ€๋ถ€๋ถ„ DP(๋™์ ๊ณ„ํš๋ฒ•) ์„ ํ™œ์šฉํ•˜์—ฌ ํ’€์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

 

Dynamic Programming (๋™์  ๊ณ„ํš๋ฒ•) ๋ฐฉ๋ฒ•

๋ชจ๋“  ์ž‘์€ ๋ฌธ์ œ๋“ค์„ ํ•œ ๋ฒˆ๋งŒ ํ’€์–ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ •๋‹ต์„ ๊ตฌํ•œ ์ž‘์€ ๋ฌธ์ œ์˜ ๋‹ต์€ ์–ด๋”˜๊ฐ€์— ๋ฉ”๋ชจํ•ด๋†“๋Š”๋‹ค. ๋‹ค์‹œ ๊ทธ ๋ณด๋‹ค ํฐ ๋ฌธ์ œ๋ฅผ ํ’€์–ด๋‚˜๊ฐˆ ๋•Œ, ๋˜‘๊ฐ™์€ ์ž‘์€ ๋ฌธ์ œ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ฉด ์•ž์„œ ๋ฉ”๋ชจํ•œ ์ž‘์€ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๊ฐ’์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด DP ์ด๋‹ค.

์ฆ‰, ์ƒํ–ฅ์‹ ์ ‘๊ทผ๋ฒ•์œผ๋กœ, ๊ฐ€์žฅ ์ž‘์€ ๋ถ€๋ถ„์˜ ํ•ด๋‹ต์„ ๊ตฌํ•œ ๋’ค ์ด๋ฅผ ์ €์žฅํ•˜๊ณ , ์ €์žฅํ•œ ๊ฐ’์„ ์ด์šฉํ•˜์—ฌ ์ƒ์œ„ ๋ฌธ์ œ๋ฅผ ํ’€์–ด๊ฐ€๋Š” ๋ฐฉ์‹์ด๋ผ๊ณ  ํ•˜๋ฉด ๋˜๊ฒ ๋‹ค. ์ด๋•Œ ๋™์ ๊ณ„ํš์˜ ํ•ต์‹ฌ์€ Memoization(๋ฉ”๋ชจ์ด์ œ์ด์…˜) ์ด๋ผ๋Š” ๊ธฐ๋ฒ•์ธ๋ฐ, ์ด์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ์•„๋ž˜์„œ ๋‹ค๋ค„๋ณด์ž.

 

Dynamic Programming (๋™์  ๊ณ„ํš๋ฒ•) ์กฐ๊ฑด

๋™์  ๊ณ„ํš๋ฒ•์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์œ„ ์ •์˜์—์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ, ๋‘ ๊ฐ€์ง€ ์†์„ฑ์„ ๋งŒ์กฑ์‹œ์ผœ์•ผ ํ•œ๋‹ค.

  • ๋ถ€๋ถ„ ๋ฐ˜๋ณต ๋ฌธ์ œ (Overlapping Subproblem)
  • ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ (Optimal Substructure)

 

โ–ถ ๋ถ€๋ถ„ ๋ฐ˜๋ณต ๋ฌธ์ œ (Overlapping Subproblem)

๋™์ ๊ณ„ํš๋ฒ•์˜ ๋“ฑ์žฅ์€ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์ด๋ผ๊ณ  ํ•œ๋‹ค. ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์€ ๋Œ€ํ‘œ์ ์ธ ์žฌ๊ท€ํ•จ์ˆ˜๋กœ, ์•„๋ž˜์™€ ๊ฐ™์ด ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

func fibo(_ n: Int) -> {
	if n <= 1 { return n }
    return fibo(n - 1) + fibo (n - 2)
}

๋งŒ์•ฝ fibo(7) ์„ ๊ตฌํ•˜๋Š” ๊ณผ์ •์„ ๋„์‹ํ™” ํ•ด๋ณด๋ฉด, ์•„๋ž˜ ์ด์ง„ ํŠธ๋ฆฌ์™€ ๊ฐ™๋‹ค.

7๋ฒˆ์งธ ๊ฐ’์„ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด 25๋ฒˆ์˜ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ณผ์ •์—์„œ fibo(5), fibo(4), fibo(3)๋“ค์ด ์ด๋ฏธ ์ง„ํ–‰ํ–ˆ๋˜ ์—ฐ์‚ฐ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์žฌ๊ท€๋˜๋ฉฐ ๋ฐ˜๋ณต์ ์œผ๋กœ ์—ฐ์‚ฐํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐ˜๋ณต์ ์ธ ์—ฐ์‚ฐ์„ ๋ถ€๋ถ„ ๋ฐ˜๋ณต ๋ฌธ์ œ (Overlapping Subproblem) ์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋Š” ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ์ชผ๊ฐœ์งˆ ์ˆ˜ ์žˆ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์šฉ์–ด์ด๋‹ค.

์ด๋•Œ ๋ถ€๋ถ„๋ฌธ์ œ (subproblem) ๋ž€ ํ•ญ์ƒ ์ƒˆ๋กœ์šด ๋ถ€๋ถ„ ๋ฌธ์ œ๋ฅผ ์ƒ์„ฑํ•ด๋‚ด๊ธฐ ๋ณด๋‹ค๋Š” ๊ณ„์†ํ•ด์„œ ๊ฐ™์€ ๋ถ€๋ถ„ ๋ฌธ์ œ๊ฐ€ ์—ฌ๋Ÿฌ๋ฒˆ ์žฌ์‚ฌ์šฉ๋˜๊ฑฐ๋‚˜ ์žฌ๊ท€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด ํ•ด๊ฒฐ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ๊ฐ€๋ฅดํ‚จ๋‹ค.

โ–ถ ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ (Optimal Substructure)

์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ๋ž€, ์ž‘์€ ๋ถ€๋ถ„ ๋ฌธ์ œ์—์„œ ๊ตฌํ•œ ์ตœ์ ์˜ ๋‹ต์œผ๋กœ ํ•ฉ์ณ์ง„ ํฐ ๋ฌธ์ œ์˜ ์ตœ์ ์˜ ๋‹ต์„ ๊ตฌํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. 

์•„๋ž˜ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด์˜ ์‹์„ ๋ณด์ž.

fibo(n) = fibo(n-1) + fibo(n-2)

ํฐ ๋ฌธ์ œ์˜ ๋‹ต์ธ fibo(n) ์ด ์ตœ์ ์˜ ๋‹ต์ด ๋˜๋ ค๋ฉด, ์ž‘์€ ๋ถ€๋ถ„์˜ ๋ฌธ์ œ์ธ fibo(n-1), fibo(n-2)์ด ์ตœ์ ์˜ ๋‹ต์ด์–ด์•ผ๋งŒ ํ•œ๋‹ค. ์ž‘์€ ๋ถ€๋ถ„์˜ ๋ฌธ์ œ์˜ ์ตœ์ ์˜ ๋‹ต์œผ๋กœ ํฐ ๋ฌธ์ œ์˜ ์ตœ์ ์˜ ๋‹ต์„ ๊ตฌํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค.

์—ฌ๊ธฐ์„œ, fibo(n-1)์„ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์‹œ fibo(n-2) + fibo(n-3)์ด ๋˜๊ณ , fibo(n-2)๊ฐ€ ์ค‘๋ณต๋˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ตœ์  ๋ถ€๋ถ„ ๊ตฌ์กฐ๋ฅผ ๋งŒ์กฑํ•œ๋‹ค๋ฉด ๋ฌธ์ œ์˜ ํฌ๊ธฐ์— ์ƒ๊ด€์—†์ด fibo(n-1)์€ ์–ธ์ œ๋‚˜ ์ผ์ •ํ•œ ๊ฐ’์„ ๊ฐ€์ง„๋‹ค.

๊ทธ๋Ÿผ ์ด ์ค‘๋ณต๋˜๋Š” ์—ฐ์‚ฐ๊ณผ์ •์„ ์ค„์ด๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ• ๊นŒ? ์ด๊ฒƒ์€ ๋ฐ”๋กœ Memoization ๊ฐœ๋…์—์„œ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Memoization (๋ฉ”๋ชจ์ด์ œ์ด์…˜)

์œ„์˜ ์ค‘๋ณต๋˜๋Š” ์—ฐ์‚ฐ๊ณผ์ •์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Memoization(๋ฉ”๋ชจ์ด์ œ์ด์…˜)์ด๋ผ๋Š” ๋™์ ๊ณ„ํš๋ฒ•์˜ ๊ฐœ๋…์ด ๋„์ž…๋˜๊ฒŒ ๋œ๋‹ค.

Memoization(๋ฉ”๋ชจ์ด์ œ์ด์…˜)์€ ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋žจ์ด ๋™์ผํ•œ ๊ณ„์‚ฐ์„ ๋ฐ˜๋ณตํ•ด์•ผํ•  ๋•Œ, ์ด์ „์— ๊ณ„์‚ฐํ•œ ๊ฐ’์„ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•จ์œผ๋กœ์จ ๋™์ผํ•œ ๊ณ„์‚ฐ์˜ ๋ฐ˜๋ณต ์ˆ˜ํ–‰์„ ์ œ๊ฑฐํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์†๋„๋ฅผ ๋น ๋ฅด๊ฒŒ ํ•˜๋Š” ๊ธฐ์ˆ ์ด๋‹ค. - Wikipedia

์ฆ‰, ๋ฉ”๋ชจ๋ฆฌ์— ๊ณ„์‚ฐํ•œ ๊ฐ’์„ ์ €์žฅํ•ด ๋‚˜๊ฐ์œผ๋กœ์จ ๋ฐ˜๋ณต ์ˆ˜ํ–‰๋  ๋•Œ ์—ฐ์‚ฐ ์—†์ด ์ €์žฅ๋œ ๊ฐ’์„ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฐœ๋…์ด๋‹ค.

์ด๋Ÿฌํ•œ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ์ด๋ผ๋Š” ๊ฐœ๋…์„, ์Šค์œ„ํ”„ํŠธ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด์„œ ๊ตฌํ˜„ํ•ด๋ณด์ž. cache๋ผ๋Š” ๋ฐฐ์—ด์„ ์ด์šฉํ•ด์„œ ๊ฐ’์„ ์ €์žฅํ•ด์ฃผ์—ˆ๋‹ค.

func fibo(_ n: Int) -> Int{
    var cache: [Int] = [0, 1]
    
    for num in 2...n {
        cache.append(cache[num - 1] + cache[num - 2])
    }
    return cache[n]
}

๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๊ณ , ๊ณ„์‚ฐํ•œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ , ์ €์žฅ๋œ ๊ฐ’์ผ ๊ฒฝ์šฐ ๋ฐฐ์—ด์˜ ๊ฐ’์„ ๋ฆฌํ„ดํ•˜๋Š” ํ˜•์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๊ฒŒ ๋˜๋ฉด ์—ฐ์‚ฐ์˜ ์ค‘๋ณต์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ ์ €์žฅ์„ ํ•ด๋‘๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ cache๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

 

๋™์ ๊ณ„ํš๋ฒ•์˜ 2๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ๋ฒ•

๋™์ ๊ณ„ํš๋ฒ•์œผ๋กœ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ๋‘ ๊ฐ€์ง€์˜ ์ ‘๊ทผ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•œ๋‹ค.

  • Bottom - up
  • Top - down

โ–ถ Bottom - up ๋ฐฉ๋ฒ•

๋ง๊ทธ๋Œ€๋กœ, ์•„๋ž˜์„œ ์œ„๋กœ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋ถ€๋ถ„ ๋ฌธ์ œ์—์„œ๋ถ€ํ„ฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์—ฌ ์ ์ฐจ ํฐ ๋ฌธ์ œ๋ฅผ ํ’€์–ด๊ฐ€๋Š” ๋ฐฉ์‹์ด๋‹ค. for ๋ฌธ์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ์ด์— ํ•ด๋‹นํ•œ๋‹ค.

var cache = [Int](repeating: 0, count : 101)

cache[1] = 1
cache[2] = 1

func fibo(_ n: Int) -> Int {
	for i in 3...n {
    	cache[i] = cache[i-1] + cache[i-2]
    }
    
    return cache[n]
}

 

โ–ถ Top - Down ๋ฐฉ๋ฒ•

๋ง๊ทธ๋Œ€๋กœ, ์œ„์—์„œ ์•„๋ž˜๋กœ ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ, ํฐ ๋ฌธ์ œ์—์„œ ๋ถ€๋ถ„ ๋ฌธ์ œ๋กœ ์ชผ๊ฐœ๊ฐ€๋ฉด์„œ ์žฌ๊ท€ ํ˜ธ์ถœ์„ ํ†ตํ•ด ๋ฌธ์ œ๋ฅผ ํ‘ธ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

//๋ฒ”์œ„๋ณด๋‹ค 1ํฌ๊ฒŒ
// cache[0] ์ดˆ๊ธฐ๊ฐ’ ์ƒํƒœ 0์œผ๋กœ ๋ชจ๋‘ ์ฑ„์›Œ์คŒ
var cache = [Int](repeating: 0, count: 101)

cache[1] = 1
cache[2] = 1

//ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด
func fibo(_ n: Int) -> Int {
	if cache[n] != 0 {
    	return cache[n]
    }
    
    cache[n] = fibo(n-1) + fibo(n-2)
    return cache[n]
}

 

 

๐Ÿ‘๐Ÿป ์ฐธ๊ณ ํ•œ ์ž๋ฃŒ, ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

https://galid1.tistory.com/507

 

์•Œ๊ณ ๋ฆฌ์ฆ˜ - Dynamic Programming(๋™์ ํ”„๋กœ๊ทธ๋ž˜๋ฐ)์ด๋ž€?

Dynamic Programming(๋™์ ๊ณ„ํš๋ฒ•) ์ด๋ž€ 1. Dynamic Programming(๋™์ ๊ณ„ํš๋ฒ•)์ด๋ž€? ํฐ ๋ฌธ์ œ๋ฅผ ์ž‘์€๋ฌธ์ œ๋กœ ๋‚˜๋ˆ„์–ด ํ‘ธ๋Š” ๋ฌธ์ œ๋ฅผ ์ผ์ปซ๋Š” ๋ง์ž…๋‹ˆ๋‹ค. ๋™์  ๊ณ„ํš๋ฒ•์ด๋ž€ ๋ง ๋•Œ๋ฌธ์— ์–ด๋–ค ๋ถ€๋ถ„์—์„œ ๋™์ ์œผ๋กœ ํ”„๋กœ๊ทธ๋ž˜

galid1.tistory.com

https://velog.io/@gillog/%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95Dynamic-Programming

 

๋™์  ๊ณ„ํš๋ฒ•(Dynamic Programming)

๋ณธ ๊ฒŒ์‹œ๊ธ€์˜ ์ตœ ์šฐ์„  ๋ชฉ์ ์€ ์ž‘์„ฑ์ž ๋ณธ์ธ์˜ ํ•™์Šต์„ ์œ„ํ•จ์ด๋ผ ๋ถ€์กฑํ•œ ์ , ํ‹€๋ฆฐ ๋ถ€๋ถ„ ๋“ฑ์ด ๋งŽ์Šต๋‹ˆ๋‹ค. ์„ ์ƒ๋‹˜๋“ค์˜ ๋”ฐ๋œปํ•œ ์กฐ์–ธ๊ณผ ํ”ผ๋“œ๋ฐฑ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๐Ÿ™‡‍โ™‚๏ธ์ฝ”๋”ฉ ํ…Œ์ŠคํŠธ ๋ฌธ์ œ๋ฅผ

velog.io

https://babbab2.tistory.com/100

 

Swift) ๋™์  ๊ณ„ํš๋ฒ• (Dynamic Programming) ์ดํ•ดํ•˜๊ธฐ

์•ˆ๋…•ํ•˜์„ธ์š”:) ์†Œ๋“ค์ž…๋‹ˆ๋‹ค ์˜ค๋žœ๋งŒ์— ํฌ์ŠคํŒ…์„ ํ•˜๋Š” ๊ฒƒ ๊ฐ™๋„ค์š”..! ์•„๋งˆ 1์›” ๋‹ฌ์—” ์ž๋ฃŒ๊ตฌ์กฐ + ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•œ ํฌ์ŠคํŒ…์ด ์ฃผ์ผ ๊ฒƒ ๊ฐ™๊ณ .. 2์›”๋‹ฌ๋ถ€ํ„ด ๋‹ค์‹œ iOS + Swift์— ๋Œ€ํ•œ ํฌ์ŠคํŒ…์„ ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค :) ์˜ค

babbab2.tistory.com

 

๋ฐ˜์‘ํ˜•