백트래킹 :가능성이 없는 곳은 패스, 가능성이 있는 곳을 탐색(=따라서, 시간복잡도는 특정 X (문제마다 효율이 달라짐))
해가 될 가능성을 판단하는 것
<-> 완전탐색 : 모든 경우의 수를 탐색하는 방법 ex) 깊이 우선 탐색, 너비 우선 탐색
백트래킹 알고리즘의 핵심 = 유망함수 : 해가 될 가능성을 판단하는 함수
1. 유효한 해의 집합을 정의
2. 위 단계에서 정의한 집합을 그래프로 표현
3. 유망 함수를 정의
4. 백트래킹 알고리즘을 활용해서 해 찾기(-> 이곳에서 찾을 것만 찾음)
가장 대표적인 문제 예시)
유망 함수가 없다면? : 경우의 수 다 확인해야함,N개의 숫자를 뽑는 조합 2^N
유망 함수 : 처음에 뽑은 숫자가 3 미만이면 탐색 X
유망 함수가 없다면? : 경우의 수 다 확인해야함
유망 함수 :
여왕이 추가될 때 -> 행, 대각선 방향에 겹치는 여왕 있으면 탐색 X
권장 시간 복잡도 : O(N!)
백트래킹인 이유?
-> 정수 N을 입력받아, 1부터 N까지의 숫자 중에서 합이 10이 되는 조합을 구하려면 원래 모든 경우의 수를 봐야함
근데 합이 10이상이면 굳이 조합할 필요없음 -> 백트래킹!
제약조건 :
def solution(N):
results = [] #진짜 조합 결과를 담을 리스트
def backtrack(sum, selected_nums, start):
if sum == 10: #합이 10이 될때만 진짜 결과 리스트에 추가
results.append(selected_nums)
return
for i in range(start, N + 1): #다음에 선택할 수 있는 숫자들을 하나씩 선택하면서
if sum + i <= 10: #선택한 숫자의 합이 10보다 작거나 같으면
backtrack(
sum + i, selected_nums + [i], i + 1
) #백트래킹 함수를 재귀적으로 호출
#else 조건, 이때 유망함수 사용, 10보다 클 경우에는 추가할 필요없음
backtrack(0, [], 1) #백트래킹 함수 호출, 한번 돌면 sum값은 항상 0으로 재시작 (* 처음에는 빈 열 값이 들어가지만, if절에 속하면 추가함)
return results # 조합 결과 반환
# TEST 코드 입니다. 주석을 풀고 실행시켜보세요
# print(solution(5)) # 반환값 : [[1, 2, 3, 4], [1, 4, 5], [2, 3, 5]]
# print(solution(2)) # 반환값 : []
# print(solution(7)) # 반환값 : [[1, 2, 3, 4], [1, 2, 7], [1, 3, 6], [1, 4, 5], [2, 3, 5], [3, 7], [4, 6]]
def check(idx, i, arr): #대각선에 있는지 체크
for j in range(idx):
if idx - j == abs(arr[j] - i):
return True
return False
def dfs(n, idx, visited, arr):#전체크기, 인덱스, visited, arr
if idx == n:#현재 인덱스가 n가 괕으면 조건 만족해서, 퀸 모두 배치
global answer
answer += 1#카운트
return#종료
for i in range(n):#n번 반복
if visited[i] == 1:#i번째 열에 퀸이 있을시
continue
if check(idx, i, arr):#대각선에 퀸이 있을시
continue
#현재 위치에 두는것 가능
arr[idx] = i#행의 상태 arr idx 에 i저장
visited[i] = 1#열 visited의 i위치를 1로 바꾸기
dfs(n, idx+1, visited, arr)# 다음 행(idx+1)로 재귀호출
visited[i] = 0#재귀호출 dfs 끝날때마다 0으로 바꿔주기(* 다시 이전 위치에서 for문을 이어나갈 수 있도록)
answer = 0
def solution(n):
visited = [0] * n #열기준
arr = [0] * n #행기준
dfs(n, 0, visited, arr)
return answer