모든 사진 자료에 관한 출처는 아래 알튜비튜 - 튜터링에 있음을 밝힙니다.
https://github.com/Altu-Bitu/Notice
즉, 답이 될 만한지(promising) 판단하고, 그렇지 않다면 탐색하지 않고 다시 전으로 넘어가서(back) 탐색을 계속 하는 것
: DFS와 Back-tracking 둘다 재귀 호출 형태로 자주 구현이 되기 때문에 헷갈린다.
두 알고리즘은 사용 목적
에 차이가 있다.
모든 노드를 방문
하는 것을 목표로 한다.불필요한 경로를 차단
하고, 이전 단계로 돌아와 다른 후보해를 탐색해 나가는 방법=> 일단 가보고 후보해가 될 수 없으면 다음 단계로 진행하지 않고 되돌아 나온다.
만일, 아래와 같은 재귀함수가 있다고 하자. 결과가 어떻게 될까?
void recursion(int n) {
if (n == 1)
return;
cout << n <<"A"<<' ';
recursion(n - 1);
cout << n <<"B"<<' ';
return;
}
int main() {
recursion(4);
}
바로, 이러한 결과가 나온다.
여기서 알수있는 것들이 몇가지 있다.
1. B는 앞의 재귀 호출함수가 완전히 마쳐지기 이전까지 출력되지 않는다.
2. 여기서 재귀함수가 완전히 마쳐진다는 것의 의미는, 그 함수가 파고 들어 결국 return문을 만났다는 것을 의미한다.
3. return 문을 만나면 가장 깊은곳에 위치한 함수부터 차례대로 그 값을 돌려받는다.
이를 그림으로 나타내면 이렇다.
나는 처음에 6번 이후에 바로 9번 과정이 이어지는것이 아닌가 생각했었다. 하지만 그렇지 않았다. 재귀함수 호출은 스택구조를 취하기 때문에 즉, 깊은곳에 있는 과업이 우선 끝 마쳐져야 더 얕은곳(?)에 있는 과업이 리턴값을 돌려받으면서 나머지 문장을 실행할 수 있게 되는것이다.
자연수 N,M이 주어졌을때 1~N까지 자연수 중 중복없이 M개를 고른 수열을 모두 구하라
1<=M<=N<=8
💡접근
제약조건을 살펴보자 -> 중복 X, 수열 길이가 M
재귀함수 설계 -> 각 수를 넣을때, 이미 수열 내에 있으면 넘어감(체크배열필요) ,기저조건은 길이가 M일때
해당 수가 현재 수열에서 사용이 되었는지 확인하는 배열필요 ->즉, 수를 인덱스로 가지는 체크배열. ->가지치기 역할
✨ 여기서 중요한 것은 백트래킹을 구현할때에는 부모노드로 돌아가기전(return문을 만나기전)에 꼭 조건을 원래 상태로 되돌려놓아야한다는 점이다. 그렇지 않으면 조건이 지속된채로 탐색이 이어져 원하지 않는 결과가 도출된다.
이를 그림으로 나타내면 이렇다.
# 백트래킹 정석
N X N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 구하는 문제
🔥 제한 사항
1 <= N < 15
💡접근
check[c]
: 세로 체크
check[c+r]
: 좌하향 대각선 체크
check[c-r+n]
: 우하향 대각선 체크
이 과정을 반복해주면, 아래그림과같이 퀸이 n개 존재할수있는 모든 경우의수를 모두 구해줄 수 있다. 구현방법에서 약간의 차이가 있지만 논리 흐름은 같다. 우리는 가로의 중복을 피하기위해서 행별로 퀸을 두었는데, 아래 그림은 열별로 퀸을 두는 경우의 수를 구한 모습이다.
🎯📳📽🎥🎬📼🛒🥅🥏🎛🧫🗑📥📝🗓🖇
⚜🔰🔬🔭▶➡α✨💷📉🗞🔖📹📝🗝🖥⌨
✒📤🧾📜📗📕📘💡💾⛏🛠🔑🔏🔊🌈🔥🚩💫❓❗🔰♻✅✔🟥🟧🟨🟩🟦🟪🔺🖼🎞🎨🎗🔑⚠❔🔀↪➰💱🔴🔴🟠🟡🟢🔵🟣🟤⚫🗨🗝🔑🔨🔐🛠🎬🕯📸🔖👾👻✔👑💎🔭🔎