Kang-JeongHyun   Jul 5, 2021 2021-07-05T12:00:00+09:00 
   Mar 29 2022-03-29T21:03:51+09:00   2 min
알고리즘 문제를 풀다보면 순열과 조합을 사용하여 모든 경우의 수를 구해봐야할 일이 많습니다. (완전탐색 / 브루트포스)
 파이썬에는 itertools 라이브러리에 해당 기능을 제공하지만 코딩테스트 환경에서 모든 경우의 수를 미리 만들어놓고 하나하나 독립적으로 처리하면 시간초과 판정을 받을 수 있습니다.
 따라서 백트래킹 기법을 사용하여 경우의 수를 동적으로 만들어가면서 변경점 위주로 처리하는 것이 시간측면에서 유리합니다.
백트래킹 (재귀)
우선 본격적인 코드를 소개하기 전에 완전탐색에 사용되는 백트래킹 기법을 간단하게 소개하겠습니다.
| 1
2
3
4
5
6
7
8
 | def back(n):
    if n == 탈출조건:
        행동수행    # (ex. print / max / min / etc...)
        return
    변화주기
    back(n+1)      # 재귀호출
    복원하기
 | 
이런 식으로 모든 경우의 수를 차례차례 탐색할 수 있습니다.
| 1
2
 | # 순열/조합에 사용할 배열
arr = [1,2,3,4,5]
 | 
순열 (nPr)
| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
 | visited = [False] * n
picked = []
def perm(n, r):
    if len(picked) == r:
        print(picked)
        return
    for i in range(len):
        if not visited[i]:
            picked.append(arr[i])   # 변화
            visited[i] = True
            perm(n, r)              # 재귀호출
            visited[i] = False
            picked.pop()            # 복원
 | 
조합 (nCr)
| 1
2
3
4
5
6
7
8
9
10
11
 | # 조합의 경우 visited가 필요없음
picked = []
def comb(n, r, left):
    if len(picked) == r:
        print(picked)
        return
    for i in range(left, n):        # left ~ n까지만 탐색
        picked.append(arr[i])       # 변화
        comb(n, r, i+1)             # 재귀호출 (마지막에 넣었던 index가 left가 된다.)
        picked.pop()                # 복원
 |