Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat : [Algorithm] DFS 알고리즘 #25

Merged
merged 4 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Algorithm/DFS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 그래프 탐색 알고리즘

## DFS

- 한 정점에서 시작
- 현재 정점과 인접한 정점 중 아직 방문하지 않은 정점을 하나 선택해 방문
- 만약 인접한 정점을 모두 방문한 상태라면 이전 정점으로 복귀
- 스택이나 재귀를 이용해서 구현할 수 있음
- 코테(PS)에서는 보통 재귀를 사용해서 구현함
- 스택을 사용하는 구현은 함수 호출 스택을 직접 구현
- 보통은 인접 리스트(c++의 vector)를 이용
![image](https://github.com/user-attachments/assets/c148ba70-dfcd-45ba-89bd-8a5513d56b4e)

- 위와 같은 방식으로 구현
- C배열은 방문 체크(check)용 배열

## DFS 와 백트래킹

- 둘 다 재귀함수를 이용해서 구현할 수 있음
- DFS는 그래프의 모든 정점을 방문해봐야하는 경우 사용
- 백트래킹은 봐야하는 부분만 보는 경우 주로 사용

## 예시 문제

![image](https://github.com/user-attachments/assets/a1753b84-5aed-4638-b4b7-5928f7e11360)

- 이분 그래프는 1학년 컴퓨터수학2과목에 다루기 때문에 생략(컴학기준)
- https://ko.wikipedia.org/wiki/%EC%9D%B4%EB%B6%84_%EA%B7%B8%EB%9E%98%ED%94%84
- 혹은 위의 링크 참조
- 요점은, 인접한 노드의 색이 달라야함
- 그래서 단순히 방문을 하는게 아니라, 색깔을 주면서 방문처리를 하면됨
![[Pasted image 20250105211437.png]]

## 추천 문제

https://www.acmicpc.net/problem/1260 : DFS와 BFS
https://www.acmicpc.net/problem/2644 : 촌수계산
https://www.acmicpc.net/problem/1707 : 이분 그래프
53 changes: 53 additions & 0 deletions Algorithm/백트래킹.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
## 백트래킹 알고리즘이란?

> 해를 찾는 도중 해가 아니어서 막히면, 되돌아가서 해를 찾아가는 기법.
> 최적화 혹은 결정 문제를 푸는 방법

- 만약 N!의 경우의 수를 가진 문제에서 최악의 경우에는 여전히 지수함수 시간이 필요해서 처리가 불가능할 수도 있음
- 즉, 모든 경우의 수 중에서 특정한 조건을 만족하는 경우만 살펴보는 것이다.
- 주로 재귀함수로 구현됨

### 예시문제 : BOJ 15649 - N과 M(1)

![image](https://github.com/user-attachments/assets/ddca3413-338b-445c-b527-6c4d07f5442f)

- 위의 문제를 보면, 무식하게 M중 중첩 반복문으로 탐색을 하고, 각 순열마다 중복 체크를 해서 해결할 수는 있다.
- 그러나, 시간제한을 보면 1초라고 명시되어 있는데, 위의 방법으로 시간복잡도를 계산해보자.
- M중 중첩 반복문을 각 자리에서 N개의 숫자를 모두 시도한다고 했을 때, O(N^M)이다.
- 각 순열마다 중복체크를 한다면 O(M)이다
- 즉, 도합 O(N^M\*M )의 시간복잡도가 걸리며, 최악의 경우 (N=8,M=8)에는 총1억3천번 정도의 연산을 하게된다
- 대충 1초 = 1억이라고 치고 계산하면 1.3초 정도 걸리는데, 이러면 시간제한을 맞출 수 없게된다

### 해결법

``` c++
void recur (int cnt) {
if(cnt==m) {
for(int i=0;i<m;i++) {
cout << A[i] << " ";
}
cout << '\n';
}
for(int i=1;i<=n;i++) {
if(vis[i])continue;
vis[i]=true;
A[cnt]=i;
recur(cnt+1);
vis[i]=false;
}
}
```

- 위와 같이 재귀호출을 이용해서 구하면 시간 복잡도가 훨씬 줄어들게 된다.
- if(vis[i])continue를 통하여 가지치기(pruning)을 거치면서 연산이 줄어들게 되는것이다.
- 요약하자면 N!/(N-M)! 정도 걸리는데, N=8,M=8인 경우 대략 4만번의 연산을 하게 되므로, 기존의 1억3천번보다 훨씬 줄어든다는 것을 알 수 있다.

## 추천 문제

### N과 M 시리즈(1~9)

https://www.acmicpc.net/problem/15650

### 연산자 끼워넣기

https://www.acmicpc.net/problem/14888