오늘은 알고리즘 스터디에서 DFS와 BFS를 사용하여 문제를 풀기로 하였다. 탐색 알고리즘인 DFS와 BFS에 대해 알아보자.
- 정점과 간선으로 구성된, 한정된 자료구조를 의미한다.
- 각가의 지점을 정점이라고 하고, 정점과 정점의 연결을 간선이라고 한다.
- 여러 개의 도시와, 도시를 연결하는 도로의 목록이 주어진다.
- 한 도시가 다른 도시와 연결되어 있는지 알 수 있는가?
- 위의 계산을 정해진 시간 내에, 효율적으로 할 수 있는가?
- 그래프가 아니지만 그래프 탐색 알고리즘을 활용해 풀 수 있는 문제.
- 데이터의 형태에 따라 정점으로 간선 대신 x,y좌표로 각 위치를 표현한다.
- NxM크기의 배열로 표현되는 미로가 주어진다.
- 미로의 출발점과 도착점은 연결되어 있는가?
- 위의 계산을 정해진 시간 내에, 효율적으로 할 수 있는가?
시작점에서 한 갈래로 더 이상 갈 수 없을 때까지 탐색하고, 더 갈 곳이 없다면 이전의 경로로 되돌아간다.
/**
* visit(node_id) : id가 node_id 인 정점을 방문한 것으로 표시
* linked_node(node_id) : 현재 정점(node_id)와 연결된 다른 정점의 목록 반환
* is_visit(node_id) : id가 node_id인 정점을 방문했는지 여부를 반환
*/
void DFS_Graph(int nodeId) {
// 방문했다는 것을 먼저 표시
visit(nodeId);
// 연결된 그래프들을 확인
for(Node node : linkedNode(nodeId)){
// 아직 방문하지 않은 경우, 재귀적으로 탐색.
if (isVist(node.getId()) != true) {
DFS_Graph(node.getId());
}
}
}
/**
* visit(x, y) : 좌표값이 x,y인 정점을 방문한 것으로 표시.
* isValid(x, y) : 좌표값이 x,y인 정정점을 방문할 수 있는지, 좌표값이 유효한지 반환
*/
void DFS_Coordinate(int x, int y) {
// 방문했다는 것을 먼저 표시
visit(x,y);
// 위로 이동
if(isValid(x, y - 1)){
DFS_Coordinate(x, y - 1);
}
// 아래로 이동
if(isValid(x, y + 1)){
DFS_Coordinate(x, y + 1);
}
// 왼쪽으로 이동
if(isValid(x - 1, y)){
DFS_Coordinate(x - 1, y);
}
// 오른쪽으로 이동
if(isValid(x + 1, y)){
DFS_Coordinate(x + 1, y);
}
}
데이터 사이즈가 일정 이상이면 DFS를 사용하지 않는 것이 좋음.
1) 큐에 저장된 정점을 하나 Dequeue한다.
2) 그리고 Dequeue된 정점과 연결된 모든 정점을 큐에 넣는다.
3) 큐가 비어있다면 반복을 종료한다.
시작점 기준으로 거리가 1인 모든 지점을 탐색하고, 이후 2인 지점을 탐색하는 식으로 모든 지점을 탐색한다.
목표 지점을 찾으면 탐색을 종료하고, 찾지 못했다면 연결된 모든 지점을 탐색한다.
/**
* visit(node_id) : id가 nodeID 인 정점을 방문한 것으로 표시
* linked_node(node_id) : 현재 정점(node_id)와 연결된 다른 정점의 목록 반환
* isVisit(node_id) : id가 nodeID인 정점을 방문했는지 여부를 반환
* targetId : 목적지의 ID 값
*/
void BFS_Graph(int startNodeId){
// 시작 지점을 먼저 넣어준다.
queue.push(startNodeId);
while(queue.isNotEmpty()) {
//위치를 하나 뽑아, 방문 처리를 해준다.
Long nodeId = queue.pop();
visit(nodeId);
if(targetId.equals(node.getId())) {
return;
}
// 연결된 다른 정점들을 순회한다.
for(Node node : linkedNode(0 nodeId)) {
if(isVisit(node.getId()) != true) {
queue.push(node.getId());
}
}
}
}
/**
* visit(x, y) : 좌표값이 x,y인 정점을 방문한 것으로 표시.
* isValid(x, y) : 좌표값이 x,y인 정정점을 방문할 수 있는지, 좌표값이 유효한지 반환
* targetPosition : 목적지 위치 좌표값
*/
void DFS_Coordinate(int x, int y) {
// 시작 지점을 먼저 넣어준다.
queue.push(new Position(start_x, start_y));
while(queue.isNotEmpty()) {
// 위치를 하나 뽑는다.
Position position = queue.pop();
// 방문 처리를 해주고, 만약 목적지라면 로직을 끝낸다.
visit(position.x, position.y);
if (tartgetPosition.Equals(position)) {
return;
}
// 위로 이동
if(isValid(position.x, position.y - 1)){
queue.push((position.x, position.y - 1);
}
// 아래로 이동
if(isValid(position.x, position.y + 1)){
queue.push((position.x, position.y + 1);
}
// 왼쪽으로 이동
if(isValid(position.x - 1, position.y)){
queue.push((position.x - 1, position.y);
}
// 오른쪽으로 이동
if(isValid(position.x + 1, position.y)){
queue.push((position.x + 1, position.y);
}
}
}
응용 알고리즘 : Flood Fill Algorithm
최단 경로를 찾을 필요 없이, 연결된 공간이 몇개인지 알아야 할 때 활용.
데이터의 크기가 크지 않은 경우, 단순한 DFS 만으로 문제를 풀 수 있다.
규모가 큰 경우 BFS를 사용하기도 함.
응용하여 풀어볼 문제
https://acmicpc.net/problem/14502
BAEKJOON Online Judge
1260 DFS와 BFS : 그래프에서 DFS / BFS연습
2606 바이러스 : 그래프에서 DFS 활용 연습
2667 단지 번호 붙이기 : DFS를 이용한 Flood Fill 연습
2178 미로탐색 : BFS로 4방향 탐색하는 연습
7569 토마토 : BFS로 6방향 탐색하는 연습
[10분 테코톡] 📚카프카의 탐색 알고리즘
위키피디아-깊이 우선 탐색 / 너비 우선 탐색
탐색알고리즘(DFS/BFS)