DFS와 BFS << 문제 클릭!
그래프를 DFS로 탐색한 결과, BFS로 탐색한 결과를 출력한다.
입력
: 정점의 개수 N(1 <= N <= 1000), 간선의 개수 M(1 <= M <= 10000), 탐색을 시작할 정점의 번호 V
: M개의 줄에는 간선이 연결하는 두 정점의 번호
출력
: 첫 번째 줄은 DFS 결과, 두 번째 줄은 BFS를 수행한 결과
: V부터 방문된 점을 순서대로 출력
조건
: 방문할 수 있는 정점이 여러 개인 경우 정점 번호가 작은 것 먼저 방문
: 더 이상 방문할 수 있는 점이 없는 경우 종료
: 정점 번호는 1번부터 N번까지
: 간선은 양방향
(2) 큐에서 pop하고 해당 노드와 인접한 노드에 대해 push(여기서 1번 4번, 노드 번호가 작은 것부터 push) 이때 한번 방문한 노드는 방문하지 않음(따로 표시를 해둬야 함!)
(3) 큐가 비어있을 때까지 2번을 반복
(2) 스택에서 pop하고 해당 노드와 인접한 노드에 대해 push (여기서는 노드 번호가 큰 것 부터 push, 따라서 4번 1번 순으로!) 이때 한번 방문한 노드는 방문하지 않음(따로 표시)
(3) 스택이 비어있을 때까지 2번을 반복
#include <iostream>
#include <queue> // 큐 사용
#include <stack> // 스택 사용
#include <vector> // 벡터 사용
#include <cstring> // memset 사용
#include <algorithm> // sort 사용
#include <utility> // pair 사용
using namespace std; // std라는 클래스의 이름 공간을 사용하겠다~~~
bool compare(const pair<int, int>& a, const pair<int, int>& b); // sort
int main(void) {
ios::sync_with_stdio(0); // c++ stream과 c stream의 동기화 제거 -> 입출력 시 시간 이득
cin.tie(0); // cin 수행 전에 buffer 지우지 않도록 해줌
int N, M, V = 0;
cin >> N >> M >> V;
int* visit = new int[N+1]; // 방문 check
memset(visit, 0, sizeof(int)*(N+1)); // 초기화 !! 안 해주면 garbage 값이 들어가서 제대로 실행 못 함
vector<pair<int, int>> graph; // 그래프
// 입력
for (int i = 0; i < M; i++) {
int f, s = 0;
cin >> f >> s;
graph.push_back(make_pair(f, s)); // 값 대입
}
sort(graph.begin(), graph.end(), compare); // 벡터 정렬 오름차순
/*DFS*/
stack<int> next;
next.push(V); // 초기값 넣기
visit[V] = 1; // 방문 표시
while (!next.empty()) // 비워질 때까지 반복
{
int node = next.top(); //맨 위의 값 확인
next.pop(); // 맨 위의 값 제거
// 연결된 노드 탐색
cout << node << " ";
for(int i = 0; i < M; i++) { // 큰 수 부터 대입
if (graph[i].first == node && visit[graph[i].second]==0) {
//fisrt가 node고 secondㄱ 방문 안 된 노드라면?
next.push(graph[i].second);
visit[graph[i].second] = 1; // 방문 완료
}
if (graph[i].second == node && visit[graph[i].first] == 0) {
//second가 node고 first가 방문 안 된 노드라면?
next.push(graph[i].first);
visit[graph[i].first] = 1; // 방문 완료
break;
}
}
}
cout << "\n"; // bfs 실행
/*BFS*/
queue<int> next_b;
next_b.push(V); // 초기값 대입
visit[V] = 0; //방문 표시
while (!next_b.empty()) // 비워질 때까지 반복
{
int node = next_b.front(); //맨 앞의 값 확인
next_b.pop(); // 맨 아래의 값 제거
cout << node << " "; // 출력
// 연결된 노드 탐색
for (int i = 0; i < M; i++) { // 작은 수 부터 대입
if (graph[i].first == node && visit[graph[i].second] == 1) {
//fisrt가 node고 secondㄱ 방문 안 된 노드라면?
next_b.push(graph[i].second);
visit[graph[i].second] = 0; // 방문 완료
}
if (graph[i].second == node && visit[graph[i].first] == 1) {
//second가 node고 first가 방문 안 된 노드라면?
next_b.push(graph[i].first);
visit[graph[i].first] = 0; // 방문 완료
}
}
}
delete[] visit;
return 0;
}
bool compare(const pair<int, int>& a, const pair<int, int>& b) {
if (a.first == b.first) {
return a.second < b.second;// 오른쪽에 있는게 더 큰 수가 되도록 정렬해라!
}
else {
return a.first < b.first;// 넘어가기
}
}
✅문제 원인
예제는 모두 해결이 되었는데 왜 해결이 안 될까 고민해보니
✅ 결론 : 간선을 vector에 단순히 pair로서 저장하는 방법을 바꿀 필요가 있다. -> 2차원 link list를 이용해보자
#include <bits/stdc++.h>
using namespace std; // std라는 클래스의 이름 공간을 사용하겠다~~~
bool compare(const pair<int, int>& a, const pair<int, int>& b); // sort
int main(void) {
ios::sync_with_stdio(0); // c++ stream과 c stream의 동기화 제거 -> 입출력 시 시간 이득
cin.tie(0); // cin 수행 전에 buffer 지우지 않도록 해줌
int N, M, V = 0;
cin >> N >> M >> V;
vector<vector<int>> graph; // 그래프
vector<int> v; // 각 노드 간 연결
int* visit = new int[N+1]; // 동적 생성
memset(visit, 0, sizeof(int) * (N+1)); // 초기화
// 초기화
for (int i = 0; i < N + 1; i++) {
graph.push_back(v); // 노드마다 생성
}
// 입력
for (int i = 0; i < M; i++) {
int f, s = 0;
cin >> f >> s;
graph[s].push_back(f); // 간선 추가
graph[f].push_back(s); // 간선 추가 하나만 추가하면 간선 그래프 끊길 수도 있음
}
/*정렬*/
for (int i = 1; i < graph.size(); i++) {
sort(graph[i].begin(), graph[i].end()); // 정렬
}
/*DFS*/
stack<int> next;
next.push(V); // 초기값 넣기
while (!next.empty()) // 비워질 때까지 반복
{
int p = next.top(); // 맨 위에 값 꺼내고
next.pop();
if (visit[p] != 1) { // 방문이 안 된 노드에 대해서만
visit[p] = 1; // 방문 표시
cout << p << " ";
for (int i = graph[p].size()-1; i >= 0; i--) {
next.push(graph[p][i]); // 해당 노드들 모두넣기
}
}
}
cout << "\n";
memset(visit, 0, sizeof(int) * (N + 1)); // 초기화
/*BFS*/
queue<int> next_b;
next_b.push(V); // 초기값 대입
visit[V] = 0; //방문 표시
while (!next_b.empty()) // 비워질 때까지 반복
{
int p = next_b.front(); // 맨 위에 값 꺼내고
next_b.pop();
if (visit[p] != 1) { // 방문이 안 된 노드에 대해서만
visit[p] = 1; // 방문 표시
cout << p << " ";
for (int i = 0; i < graph[p].size(); i++) {
next_b.push(graph[p][i]); // 해당 노드들 모두넣기
}
}
}
delete[] visit;
return 0;
}
아주 좋아~~
다른 분들의 풀이 출처
#include<iostream>
#include<queue>
using namespace std;
#define MAX_VALUE 1001 //'N이 1~1000 이므로 1000번째 인덱스에 접근 -> 크기 1001까지 선언
int N, M, V; //노드 개수, 간선 개수, 시작할 노드 번호
int mat[MAX_VALUE][MAX_VALUE]; //인접행렬 배열 선언
int visit[MAX_VALUE]; //visit 배열 default 는 0으로. . .
void dfs(int v) {
cout << v << ' ' ;
visit[v] = 1; //방문한 노드를 visit 0에서 1로 변경
for(int i=1; i<=N; i++) {
if(visit[i] == 1 || mat[v][i] == 0)
continue;
dfs(i); //dfs에서 재귀를 사용
}
}
void bfs(int v) {
queue<int> q; //bfs에서는 q를사용
q.push(v);
visit[v] = 0; //방문한 노드를 visit 1에서 0으로 변경
while(!q.empty()) {
v = q.front();
cout << q.front() << ' ';
q.pop();
for(int i=1; i<=N; i++) {
if(visit[i] == 0 || mat[v][i] == 0) // 방문한 노드 혹은 인접 노드 아닌 경우
continue;
q.push(i);
visit[i] = 0;
}
}
}
int main() {
int x, y;.
cin >> N >> M >> V; //N은 노드개수, M은 간선의개수, V는 처음 위치의 기준이 되는 노드
for(int i=0; i<M; i++) { //간선의 개수만큼 서로 이어줄 x와 y노드를 입력받습니다.
cin >> x >> y;
mat[x][y] = mat[y][x] = 1; //인접행렬 표시
}
dfs(V);
cout << '\n';
bfs(V);
return 0;
}