Computer Science/Algorithms

๐Ÿ™ƒ Backtracking

metamong 2024. 1. 18.

intro

๐Ÿ™ƒ backtracking์ด๋ž€, ํ˜„์žฌ ์ƒํƒœ์—์„œ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ํ›„๋ณด๊ตฐ์„ ๋”ฐ๋ผ ๋“ค์–ด๊ฐ€๋ฉฐ ํƒ์ƒ‰ํ•˜๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜. ๊ตฌํ˜„๋ ฅ์„ ํ•„์š”๋กœ ํ•œ๋‹ค. ํ˜„์žฌ์—์„œ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ๋ชจ์•„ ๋‘” decision space๋ฅผ ๋งŒ๋“ค๊ณ , decision space์˜ ๊ฐ ๋ถ€๋ถ„๋งˆ๋‹ค ๋ป—์–ด ๋‚˜๊ฐ€๋ฉฐ ๊ทธ ๋‹ค์Œ์œผ๋กœ ๋‚˜์˜ค๋Š” deicision space์—์„œ ๊ณ„์†ํ•ด์„œ ๋ป—์–ด๋‚˜๊ฐ€๋ฉฐ ํƒ์ƒ‰. ๋งŒ์•ฝ ๋ป—์–ด๋‚˜๊ฐ„ ๊ฒฐ๊ณผ ๋ฌธ์ œ ์ƒํ™ฉ์— ๋งž์ง€ ์•Š์œผ๋ฉด, ๊ทธ ์ž๋ฆฌ์—์„œ ์ค‘๋‹จํ•˜๊ณ  ๋‹ค์‹œ ๋’ค๋กœ ํ›„ํ‡ดํ•˜๋ฉด์„œ ์˜ฌ๋ผ๊ฐ€ ๋˜ ๋‹ค๋ฅธ ๊ฒฝ์šฐ์˜ ์ˆ˜๋กœ ๋ป—์–ด๋‚˜๊ฐ€๋ฉฐ ํƒ์ƒ‰. 

 

๐Ÿ™ƒ ์ฆ‰, ์š”์•ฝํ•˜์ž๋ฉด ์žฌ๊ท€์ ์œผ๋กœ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  case๋ฅผ incrementallyํ•˜๊ฒŒ ํƒ์ƒ‰ํ•ด๋‚˜๊ฐ€๋ฉด์„œ ํ•ด๋‹น ๋ฌธ์ œ ์กฐ๊ฑด์— ๋งŒ์กฑํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ์ด์ „์œผ๋กœ ๋Œ์•„๊ฐ€(backtrack) ๊ณ„์† ์†”๋ฃจ์…˜์„ ์ฐพ๋Š” ๊ธฐ๋ฒ•(๊ฒฐ๋ก : ๋ฐฑํŠธ๋ž˜ํ‚น์€ ๊ทธ๋ƒฅ ๋ฌธ์ œ ๋งŽ์ด...). DFS์™€ ๋‹ค๋ฅธ ์ ์€, DFS๋Š” ๋ชจ๋“  case๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ฉฐ ๋ป—์–ด๋‚˜๊ฐ€์ง€๋งŒ, backtracking์€ ๋ป—์–ด๋‚˜๊ฐ€๋Š” ๋„์ค‘ ๋งž์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฒ€์ƒ‰ ์—†์ด ๋ฐ”๋กœ ์ค‘๋‹จ. ๋”ฐ๋ผ์„œ ๋ฐฑํŠธ๋ž˜ํ‚น์ด๋ผ๋ฉด ์ด๋ฏธ ์ง€๋‚˜์ณ์˜จ ๊ณณ์„ ๋‹ค์‹œ ๋Œ์•„๊ฐ€์„œ ๋‹ค๋ฅธ ๊ฐ€๋Šฅ์„ฑ์„ ์‹œ๋„ํ•ด๋ณด๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ๋ฌด์ž‘์ • ๋ชจ๋“  case๋ฅผ ์ผ์ผ์ด ํ™•์ธํ•˜๋Š” brute-force์™€๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค. backtracking์€ ๊ณผ๊ฑฐ์™€ ๋ฏธ๋ž˜ ์ƒํƒœ๋ฅผ ๋ชจ๋‘ ๊ณ ๋ คํ•˜์—ฌ ๋ป—์–ด๋‚˜๊ฐ€๊ฑฐ๋‚˜ ๊ฐ€์ง€์น˜๊ธฐํ•˜๋Š” ํƒ์ƒ‰ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ brute-force๋ณด๋‹ค ์„ฑ๋Šฅ์ด ๋” ์ข‹์œผ๋ฉฐ, ์ด ๋•Œ ์žฌ๊ท€๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์“ฐ์ธ๋‹ค. ๋”ฐ๋ผ์„œ ๊ตฌํ˜„์ด ์ƒ๋‹นํžˆ ์–ด๋ ต..

backtracking example

โ‘  N๊ณผ M ๊ธฐ์ดˆ((1) ~ (8))

๐Ÿ™ƒ ๋Œ€ํ‘œ ๋ฌธ์ œ BOJ N๊ณผ M (1)์„ ์š”์•ฝํ•˜๋ฉฐ backtracking ์žฌ๊ท€์— ์ต์ˆ™ํ•ด์ง€์ž.

 

โ€ป BOJ 15649 N๊ณผ M (1)

Q. ์ž์—ฐ์ˆ˜ N๊ณผ M์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ์•„๋ž˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ธธ์ด๊ฐ€ M์ธ ์ˆ˜์—ด ๋ชจ๋‘ ๊ตฌํ•˜๊ธฐ

์กฐ๊ฑด โ‘ ) ์ค‘๋ณต๋˜๋Š” ์ˆ˜์—ด์€ ๋”ฑ 1๋ฒˆ๋งŒ ์ถœ๋ ฅ

์กฐ๊ฑด โ‘ก) ์ˆ˜์—ด์€ ์‚ฌ์ „ ์ˆœ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๋Š” ์ˆœ์„œ๋กœ ์ถœ๋ ฅ

(์ด ๋•Œ 1๋ถ€ํ„ฐ N๊นŒ์ง€์˜ ์ž์—ฐ์ˆ˜์—์„œ ์ˆ˜์—ด ๋งŒ๋“ค๊ธฐ)

 

(1)

→ track()๊ณผ backtrack ์žฅ์น˜๋ฅผ ๊ฐ๊ฐ ๊ธฐ์–ตํ•ด์ฃผ๋ฉด ๋œ๋‹ค. track()์ด๋ผ๋Š” ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€๋Š” ํŒŒ๋ž€์ƒ‰ ํ™”์‚ดํ‘œ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ recursion

→ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ backtracking โ‘  ๋„์ค‘์— ์กฐ๊ฑด์— ๋งž์ง€ ์•Š์•„ ๋ฐ”๋กœ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€๋Š” backtracking / โ‘ก ์ •๋‹ต์„ ๋ชจ๋‘ ๊ตฌํ•ด ํ•ด๋‹น case๊ฐ€ ๋‹ค ๋๋‚˜ ๋‹ค์‹œ ์˜ฌ๋ผ๊ฐ€๋Š” backtracking: ์ด ๋•Œ ๋‹ค์‹œ ์˜ฌ๋ผ๊ฐ€๊ธฐ ์œ„ํ•ด์„œ ์œ„ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ans.pop()๊ณผ ๊ฐ™์€ ์žฅ์น˜ track() ์ดํ›„ ๋งŒ๋“ค์–ด์ค˜์•ผ ํ•œ๋‹ค.

N,M=map(int,input().split())
ans=[]
def track():
    if len(ans) == M: #completed
        print(*ans)
    else:
        for x in range(1,N+1):
            if len(ans) != 0 and x in ans:
                continue #backtrack 1
            else:
                ans.append(x)
                track()
                ans.pop() #backtrack 2
track()

: ํ•จ์ˆ˜ ๋๋‚˜๋Š” if๋ฌธ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด backtrack 1 ๋ฐ”๋กœ ํ•  ๊ฒƒ์ธ์ง€ if๋ฌธ → backtrack1 ์•ˆํ•œ๋‹ค๋ฉด track() ๋‚ด๋ ค๊ฐ€๊ธฐ + track() ๋‚ด๋ ค๊ฐ€๊ธฐ ์ดํ›„ ์˜ฌ๋ผ๊ฐ€๊ธฐ ์ฝ”๋“œ

 

(2)

→ ๋˜๋Š”, ๋„์ค‘์— ๊ฐ€์ง€์น˜๊ธฐ ๋˜๋Š” backtracking์„ ๋ช…์‹œ์ ์œผ๋กœ continue๋ฌธ ๊ตฌํ˜„ ํ•„์š” ์—†์ด track() ๋˜๋Š” ๋ถ€๋ถ„๋งŒ ๋Œ๋ ค / ๋‹ต์„ ๊ตฌํ•˜๊ณ  ๋‚œ ๋’ค ์ญ‰ ์˜ฌ๋ผ๊ฐ€๋Š” backtrack ์žฅ์น˜๋งŒ ๋งŒ๋“ค์–ด๋„ OK

N,M=map(int,input().split())
ans=[]
def track():
    if len(ans) == M: #completed
        print(*ans)
    else:
        for x in range(1,N+1):
            if len(ans) == 0 or x not in ans:
                ans.append(x)
                track()
                ans.pop() #backtrack
track()

โ‘ก N๊ณผ M ์‹ฌํ™”((9)~(12))

โ€ป BOJ 15663 N๊ณผ M (9)

Q. ์ž์—ฐ์ˆ˜ N๊ณผ M์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ์•„๋ž˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๊ธธ์ด๊ฐ€ M์ธ ์ˆ˜์—ด ๋ชจ๋‘ ๊ตฌํ•˜๊ธฐ

์กฐ๊ฑด โ‘ ) ์ค‘๋ณต๋˜๋Š” ์ˆ˜์—ด์€ ๋”ฑ 1๋ฒˆ๋งŒ ์ถœ๋ ฅ

์กฐ๊ฑด โ‘ก) ์ˆ˜์—ด์€ ์‚ฌ์ „ ์ˆœ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๋Š” ์ˆœ์„œ๋กœ ์ถœ๋ ฅ

(์ด ๋•Œ ์ค‘๋ณต์„ ํฌํ•จํ•œ,๋žœ๋คํ•œ N๊ฐœ์˜ ์ž์—ฐ์ˆ˜์—์„œ ์ˆ˜์—ด ๋งŒ๋“ค๊ธฐ)

 

๐Ÿ™ƒ ์žฌ๊ท€์ ์œผ๋กœ ๋„๋Š” backtracking์—์„œ ์ฃผ์–ด์ง„ ๋ฐฐ์—ด์—์„œ ์ž์—ฐ์ˆ˜๋Š” ์ตœ๋Œ€ 1๋ฒˆ๋งŒ ์“ฐ์ด๊ณ  ์ˆ˜์—ด ์ค‘๋ณต ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ์œ„์˜ ๊ธฐ์ดˆ backtracking์—์„œ ์žฅ์น˜๋ฅผ ๋ช‡ ๊ฐ€์ง€ ๋” ๋งŒ๋“ค์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. (1) visited [] ์‚ฌ์šฉํ•˜์—ฌ not visitedํ•œ ๊ณณ๋งŒ ์žฌ๊ท€ ์ง„ํ–‰. ์ด ๋•Œ ์žฌ๊ท€ ์ „ visited = True ์„ค์ •ํ•˜๊ณ , ์žฌ๊ท€ ํ•จ์ˆ˜ ์•„๋žซ์ค„, ์ฆ‰ ์žฌ๊ท€ ์ดํ›„์—๋Š” pop()๊ณผ ํ•จ๊ป˜ visited = False ๊ผญ ์„ค์ • ํ•„์š” (์ด์ „ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆฌ๊ธฐ์ด๋ฏ€๋กœ) / (2) ์ˆ˜์—ด ์ค‘๋ณต ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋ฐ”๋กœ ์•ž์˜ ์›์†Œ, ์ฆ‰ ๋งˆ์ง€๋ง‰ ์›์†Œ last๋งŒ ๋น„๊ตํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ ์ด์œ ๋Š” ์žฌ๊ท€์˜ ํŠน์„ฑ์ƒ, ๋ฐ”๋กœ ์•ž์˜ ์›์†Œ์™€ ๊ฐ™์ง€ ์•Š๋‹ค๋ฉด ๊ทธ ์•„๋ž˜ ์ญ‰ ํƒ์ƒ‰์„ ์•ˆํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ.  

import sys
input=sys.stdin.readline
N,M=map(int,input().split())
nums=list(map(int,input().split()))
nums.sort()
num,visited=[],[False]*N
def track():
    if len(num)==M:
        print(*num)
    else:
        last=0
        for i in range(len(nums)):
            if not visited[i] and last!=nums[i]:
                visited[i]=True
                num.append(nums[i])
                last=nums[i]
                track()
                num.pop()
                visited[i]=False
track()

โ‘ข N๊ณผ M BOJ ์ •๋ฆฌ

Q. N๊ฐœ์˜ ์ž์—ฐ์ˆ˜ ์ค‘์— ์กฐ๊ฑด์— ๋งŒ์กฑํ•˜๋Š” M๊ฐœ์˜ ์ˆ˜์—ด์„ ์ถœ๋ ฅํ•˜๋Š” ๋ฌธ์ œ


BaaaarkingDog

 

 

 

 

 

'Computer Science > Algorithms' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

๐Ÿก Two Pointers  (1) 2024.02.11
๐Ÿฆœ Pigeonhole Principle  (0) 2024.02.02
๐Ÿงฟ Dijkstra's (Shortest Path) Algorithm  (1) 2024.01.14
๐ŸLIS(Longest Increasing Subsequence) O(n^2)/O(nlogn)  (0) 2024.01.06
๐Ÿ“กKadane's Algorithm  (0) 2024.01.03

๋Œ“๊ธ€