처음 보는 백트래킹 문제라서
개념부터 공부 할 필요가 있었다.
백트래킹
모든 경우의 수를 확인할 때
for
로는 확인 불가한 경우 (깊이가 달라질 때)
예를 들어, N개의 숫자 중 M개의 숫자를 골라야 할 때def a(num) if num == M return for 1부터 N까지 결과값 추가 + 방문여부 체크 a(num + 1)
의 방식으로 구현 가능하다는 것 ...?
- 재귀함수는 트리 구조로 이해하는 것이 편하다
- 백트래킹 문제는 N이 작음
- 재귀함수 쓸 때, 종료 시점 잊지 않기
대충 강의에서는 그렇게 설명하는데
직접 풀어보기로 했다.
자연수 N과 M이 주어졌을 때, 아래 조건을 만족하는 길이가 M인 수열을 모두 구하는 프로그램을 작성하시오.
첫째 줄에 자연수 N과 M이 주어진다. (1 ≤ M ≤ N ≤ 8)
한 줄에 하나씩 문제의 조건을 만족하는 수열을 출력한다. 중복되는 수열을 여러 번 출력하면 안되며, 각 수열은 공백으로 구분해서 출력해야 한다.
수열은 사전 순으로 증가하는 순서로 출력해야 한다.
1부터 N까지 for
돌면서 숫자 중 하나 선택
다시 1부터 N까지 숫자 중 하나 선택, 이미 선택한 값이 아니어야 함
선택한 숫자의 개수가 M에 도달하면 print
import sys
input = sys.stdin.readline
N, M = map(int, input().split())
ans = []
visit = [False] * (N + 1)
여기서부터는 backtracking
기본 패턴이므로 몸에 익히기
def recur(num):
if num == M:
print(' '.join(map(str, ans)))
return
for i in range(1, N+1):
if visit[i] == False:
visit[i] = True
ans.append(i)
recur(num + 1)
visit[i] = False
ans.pop()
recur(0)
위 코드에서,
visit[i] = False
ans.pop()
부분이 빠지면, [1,2]
에서 멈추지 않고 [1,2,3]
까지 출력하게 되기 때문에 반드시 방문 여부인 visit
을 False
로 변경하고 pop()
함수를 사용해 제거해 주도록 하자.
sys.stdin.readline
이랑 백트래킹 기본 구조는 빨리 손에 익히자