[백준/BOJ] - 1260번 DFS와 BFS (C++/DFS BFS)
2024. 11. 12. 20:56ㆍ카테고리 없음
01. 문제
https://www.acmicpc.net/problem/1260
문제설명
1. 그래프를 DFS로 탐색한 결과와 BFS로 탐색한 결과를 출력하는 프로그램을 작성하시오. 단, 방문할 수 있는 정점이 여러 개인 경우에는 정점 번호가 작은 것을 먼저 방문하고, 더 이상 방문할 수 있는 점이 없는 경우 종료한다. 정점 번호는 1번부터 N번까지이다.
2. 첫째 줄에 정점의 개수 N(1 ≤ N ≤ 1,000), 간선의 개수 M(1 ≤ M ≤ 10,000), 탐색을 시작할 정점의 번호 V가 주어진다. 다음 M개의 줄에는 간선이 연결하는 두 정점의 번호가 주어진다. 어떤 두 정점 사이에 여러 개의 간선이 있을 수 있다. 입력으로 주어지는 간선은 양방향이다.
02. 문제 접근 과정 📖
예제 입력에서 인접 행렬 방식이 아닌 인접 리스트 방식으로 주므로 Vector로 만들어서 받으면 될 것 같다.
그 후 인접 리스트로 구현된 노드들을 DFS BFS 돌리면 될듯
*간선 양방향 이므로 주의하자
03. 문제 풀이 ✏️
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
int N, M, V;
int Node, Val;
vector<int> graph[1001];
bool visit[1001]{ false, };
void dfs(int _x)
{
visit[_x] = true;
cout << _x << ' ';
for(auto& x : graph[_x])
{
if(!visit[x])
{
dfs(x);
}
}
}
void bfs(int _x)
{
queue<int> q;
q.push(_x);
while (!q.empty())
{
int temp = q.front();
q.pop();
visit[temp] = true;
cout << temp << ' ';
for(auto& x : graph[temp])
{
if(!visit[x])
{
q.push(x);
visit[x] = true;
}
}
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> N >> M >> V;
for(int i=0; i<M; ++i)
{
cin >> Node >> Val;
graph[Node].push_back(Val);
graph[Val].push_back(Node);
}
for (int i = 1; i <= N; ++i) {
sort(graph[i].begin(), graph[i].end());
}
dfs(V);
//memset(visit, false, sizeof(visit));
fill_n(visit, 1001, false);
cout << '\n';
bfs(V);
return 0;
}
위에 처럼 풀었지만 메모리를 너무 잡아먹는다!
그래서 조금 최적화는 한다면
1. 배열을 다이나믹으로 설정해서 노드 수에 맞게 벡터 동적으로 설정하자
03.1 최적화 풀이 ✏️
인접 리스트 방식에서 인접 행렬 방식으로 변경하면.. 쪼금 빨리질것 같지만 유의미한 차이는 없을 것 같다.
배열을 다이나믹으로 식으로 변경하면.. 더 느려질것 같지만 최적화 관점에서는 더 좋으므로..
여기서 M과 N 값이 다를 수 있다는 관점이 있다
이러면 graph는 1000까지 도는데 visit은 overflow 나므로 visit은 고정으로 1001로 설정하자~
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
int N, M, V;
int Node, Val;
vector<vector<int>> graph;
vector<bool> visit{ false, };
void dfs(int _x)
{
visit[_x] = true;
cout << _x << ' ';
for( auto& x : graph[_x])
{
if(!visit[x])
{
dfs(x);
}
}
}
void bfs(int _x)
{
queue<int> q;
q.push(_x);
visit[_x] = true;
while (!q.empty())
{
int temp = q.front();
q.pop();
cout << temp << ' ';
for(auto& x : graph[temp])
{
if(!visit[x])
{
q.push(x);
visit[x] = true;
}
}
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cin >> N >> M >> V;
graph.resize(N + 2);
visit.resize(1001);
for(int i=0; i<M; ++i)
{
cin >> Node >> Val;
graph[Node].push_back(Val);
graph[Val].push_back(Node);
}
for (int i = 1; i <= N; ++i) {
sort(graph[i].begin(), graph[i].end());
}
dfs(V);
//memset(visit, false, sizeof(visit));
//fill_n(visit, 1001, false);
fill(visit.begin(), visit.end(), false);
cout << '\n';
bfs(V);
return 0;
}
여기서 신기한게 vector<bool> 을 fill_n 으로 초기화 시킬 수 없었다.....
fill_n 으로 visit vect를 초기화 시키면 해당 오류가 난다.
'초기화 중': 'const _Diff'에서 '__int64'(으)로 변환할 수 없습니다.
이유를 조금 설명하자면...
다들 아시다 시피 std::vector는 다이나믹 타입으로 T 타입인데, vector<bool> 은 메모리 효율성을 위해서 위 방식을 사용하지 않는다...
그래서 한 바이트에 여러 개의 불리언 값을 저장하는 방식으로 구현된다. (와우)
vector<bool>은 bool 요소를 효율적으로 저장하기 위해 실제 bool 변수가 아닌 특수한 proxy 객체로 사용한다 그리고 이걸 인터페이스로 우리에게 제공한다 여기서!
bool& , const bool& 을 반환하는게 아니라
std::vector<bool>::reference 를 반환한다!
fill_n 함수는 iterator를 지원하지 않으므로 fill로 해야한다....
04. 결론
fill_n 이 참 신기하네요..