Graph의 탐색 - DFS, BFS(작성중)
그래프 탐색의 목적
그래프의 모든 정점 을 한번씩 방문하기 위해!
그래프 탐색 알고리즘
- 깊이 우선 탐색(Depth First Search, DFS)
- 한 길을 깊이 파고 들어 더 이상 갈 수 없으면 이전 정점으로 돌아감.
- stack 이용
- 너비 우선 탐색(Breadth First Search, BFS)
- 현재 정점이 갈 수 있는 모든 정점을 방문하는 것(동시에)
- queue 이용
DFS
설명
-
stack 과 실제로 한번씩 방문 한 것이 맞는지 확인을 위한 배열 을 이용한다.
- 갈 수 있는 만큼 최대한 많이 가고, 더 이상 갈 수 없다면 stack을 통해 이전 정점으로 돌아간다.
-
방문의 우선 순위는 정하기 나름이다.
코드 짜는 사람 맴이지롱
- 현재 정점은 1이고 stack에는 1이 있다. 다음으로 갈 수 있는 정점은 2,3,4가 있는데 여기서는 가장 작은 정점을 우선적으로 가는 걸로 하겠다.
- 정점 2를 방문하였고, stack에는 2를 push한다.
- 2에서 방문 가능한 정점, 3을 방문했고 stack에는 3이 push 된다.
- 3에서 방문 가능한 정점 5, 6 중 작은 숫자인 정점 5를 방문하고 5를 push한다.
- 5에서 방문 가능한 정점 6을 가고, stack에 6을 push 한다.
- 정점 6에서 더 이상 갈 수 있는 곳이 없다.
- stack을 이용하여 이전 정점으로 되돌아간다.
- 아래의 경우 pop을 하면 head값이 5가 되므로, 정점 5로 돌아간다.
- 정점 5에서 더 이상 갈 수 있는 곳이 없으므로 stack에서 5를 pop하여 정점 3으로 돌아간다.
- 정점 3에서 더 이상 갈 수 있는 곳이 없으므로 stack에서 3를 pop하여 정점 2로 돌아간다.
- 정점 2에서 더 이상 갈 수 있는 곳이 없으므로 stack에서 2를 pop하여 정점 1로 돌아간다.
- 정점 1에서 4로 갈 수 있으므로 정점 4를 방문하고 stack에 4를 push한다.
- 정점 4에서 더 이상 갈 수 있는 곳이 없으므로 pop하여 정점 1로 돌아간다.
- 정점 1에서 더 이상 갈 수 있는 곳이 없어 pop을 하면 stack이 비게 된다. stack이 비게 되면 탐색을 종료한다.
BFS
설명
-
queue 와 실제로 한번씩 방문 한 것이 맞는지 확인을 위한 배열 을 이용한다.
- DFS에서는 실제로 정점을 방문 했을 경우에 해당 정점을 stack에 push하고 배열의 값을 1로(방문의 표시) 바꿔주었다.
- 하지만 BFS에서는 지금 위치에서 갈 수 있는 모든 정점을 큐에 넣고, 큐에 넣었을 때 배열의 값을 1로 (방문했다고 표시) 바꿔주어야 한다.(즉, 실제로 아직 방문하지 않았지만 큐에 넣고, 배열에도 체크 해줘야 한다는 말)
- 현재 정점은 1이고, 큐에는 1을 넣어준다.
- 1에서 갈 수 있는 모든 정점(2,3,4)를 큐에 넣고 배열의 값도 1로 바꿔줍니다.
- 그리고 1을 큐에서 제거하고 다음 front의 값인 2를 현재 정점으로 합니다.
- 2에서는 갈 수 있는 곳이 없으므로, 큐에서 2를 제거하고 현재 정점은 3이 됩니다.
- 3에서는 정점 5와 6에 갈 수 있으므로, 5와 6을 큐에 넣고 배열에 1로 체크 해 줍니다.
- 3을 큐에서 제거하고 현재 정점은 4가 됩니다.
- 4에서는 더 이상 갈 수 있는 곳이 없으므로, 큐에서 빠져나오고 현재 정점은 5가 됩니다.
- 5에서는 더 이상 갈 수 있는 곳이 없으므로, 큐에서 빠져나오고 현재 정점은 6이 됩니다.
- 6에서는 더 이상 갈 수 있는 곳이 없으므로, 큐에서 빠져나오고 큐는 비어있게 됩니다. 큐에 아무것도 없으면 탐색 완료!
문제 풀어 보기(구현)
-
인접 행렬을 이용한 풀이
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556#include <queue>#include <cstdio>#include <vector>#include <cstring>using namespace std;bool check[1001];int matrix[1001][1001];int n;queue<int> q;void dfs(int v) {printf("%d ", v);check[v] = true;for (int i = 1; i <= n; i++) {if (matrix[v][i] == 1 && check[i] == false) {dfs(i);}}}void bfs(int v) {memset(check, false, sizeof(check));q.push(v);check[v] = true;while (!q.empty()) {int current = q.front();printf("%d ", current);for (int i = 1; i <= n; i++) {if (matrix[current][i] == 1 && check[i] == false) {check[i] = true;q.push(i);}}q.pop();}}int main() {int m, v;scanf("%d %d %d", &n, &m, &v);for (int i = 0; i < m; i++) {int r, c;scanf("%d %d", &r, &c);matrix[r][c] = 1;matrix[c][r] = 1;}dfs(v);printf("\n");bfs(v);return 0;}cs - dfs의 경우에는 재귀 함수를 이용하였다.
- 정점의 개수가 1부터 1000까지의 값을 가질 수 있으므로 배열을 1001까지로 만들어서 배열 인덱스를 1부터 1000까지 다 접근 할 수 있도록 만들었다.
-
인접 리스트를 이용한 풀이
-
재귀 함수 이용
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061#include <cstdio>#include <queue>#include <algorithm>#include <cstring>using namespace std;bool check[1001];vector<int> list[1001];queue<int> q;void dfs(int v) {printf("%d ", v);check[v] = true;for (int i = 0; i < list[v].size(); i++) {int next = list[v][i];if (check[next] == false) {dfs(next);}}}void bfs(int v) {memset(check, false, sizeof(check));q.push(v);check[v] = true;while (!q.empty()) {int current = q.front();printf("%d ", current);for (int i = 0; i < list[current].size(); i++) {int next = list[current][i];if (check[next] == false) {q.push(next);check[next] = true;}}q.pop();}}int main() {int n, m, v;scanf("%d %d %d", &n, &m, &v);for (int i = 0; i < m; i++) {int r, c;scanf("%d %d", &r, &c);list[r].push_back(c);list[c].push_back(r);}for (int i = 1; i <= n; i++) {sort(list[i].begin(), list[i].end());}dfs(v);printf("\n");bfs(v);return 0;}cs - sort가 들어간 이유는, 문제의 조건에 ‘방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고’라는 말이 있기 때문이다.
-
stack 이용
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374#include <cstdio>#include <queue>#include <stack>#include <algorithm>#include <cstring>using namespace std;bool check[1001];vector<int> list[1001];queue<int> q;stack<int> s;void dfs(int v) {check[v] = true;s.push(v);printf("%d ", v);while (!s.empty()) {int current = s.top();int i = 0;for (; i < list[current].size(); i++) {int next = list[current][i];if (check[next] == false) {printf("%d ", next);check[next] = true;s.push(next);break;}}if (i == list[current].size()) {s.pop();}}}void bfs(int v) {memset(check, false, sizeof(check));q.push(v);check[v] = true;while (!q.empty()) {int current = q.front();printf("%d ", current);for (int i = 0; i < list[current].size(); i++) {int next = list[current][i];if (check[next] == false) {q.push(next);check[next] = true;}}q.pop();}}int main() {int n, m, v;scanf("%d %d %d", &n, &m, &v);for (int i = 0; i < m; i++) {int r, c;scanf("%d %d", &r, &c);list[r].push_back(c);list[c].push_back(r);}for (int i = 1; i < n; i++) {sort(list[i].begin(), list[i].end());}dfs(v);printf("\n");bfs(v);return 0;}cs - 30 ~ 32 의 if 문 : i의 값이 정점 n에 연결된 정점들의 개수와 같다면 해당 정점에서 더 이상 갈 수 있는 곳이 없음을 의미하므로 pop을 해준다.
-
-
간선의 정보를 이용
응용
-
연결 요소 찾기
-
이분 그래프
아직 배움의 과정에 있는 학생이니 내용에 부족한 점이 보이면 지적은 하되, 비난은 하지 말아주세요!!
</html>
댓글남기기