문제 풀이에 대한 오류 지적 및 개선 방향 제시는 항상 환영합니다.
알고리즘 문제를 엄청 잘 풀고 막 문제 보자마자 아 이거네 쉽네 ㅎㅎ 이렇게 푸는 입장이 아니라서
그 어떤 문제에 대한 비판 지적 방향 제시는 언제나 감사하게 받겠습니다.
이 문제가 올라가는 저장소 : https://github.com/hwk0911/junit-tdd
n개의 노드가 있는 그래프가 있습니다. 각 노드는 1부터 n까지 번호가 적혀있습니다. 1번 노드에서 가장 멀리 떨어진 노드의 개수를 구하려고 합니다. 가장 멀리 떨어진 노드란 최단경로로 이동했을 때 간선의 개수가 가장 많은 노드들을 의미합니다.
노드의 개수 n, 간선에 대한 정보가 담긴 2차원 배열 vertex가 매개변수로 주어질 때, 1번 노드로부터 가장 멀리 떨어진 노드가 몇 개인지를 return 하도록 solution 함수를 작성해주세요.
n | vertex | return |
6 | [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] | 3 |
예제의 그래프를 표현하면 아래 그림과 같고, 1번 노드에서 가장 멀리 떨어진 노드는 4,5,6번 노드입니다.
문제를 해결하기 위해서는 당연히 그래프를 그릴 수 있어야 하며, 해당 문제를 읽고
이 문제에 적합한 탐색방법을 찾을 수 있어야 수월하게 풀 수 있다.
우리가 기본적으로 그래프에 관련된 문제가 나왔을 때, 주로 DFS와 BFS를 떠올릴 것이다.
DFS의 경우, 깊이 우선 탐색으로, 말 그대로 우선 최대한 깊게 내려가는 것을 목표로 하는
탐색 방법이다. 주로 미로를 탐색하거나, 모든 노드를 방문하고자 할 때 사용한다.
BFS의 경우, 너비 우선 탐색으로, 말 그대로 깊이가 아닌, 너비를 우선으로 탐색하는 방법이다.
쉽게 말해, 한층 한층 검사를 한다 생각하면 쉽다. 주로 두 노드의 최단 혹은 임의의 경로를 찾을 때
사용한다.
아직 어떤 것이 더 효율적인지 감이 잡히지 않았다면, 문제를 살펴보자.
이 문제의 핵심 요구사항은, 1번 노드에서 가장 멀리 떨어진 노드의 개수를 구하는 것이다.
특정 노드에서 가장 멀리 떨어져 있다 => 최단 경로에서 간선의 개수가 가장 많은 노드로 볼 수 있다.
여기서 DFS를 사용하지 못하는 가장 중요한 조건이 나온다. 최단 경로.
DFS의 경우, 탐색 후 나온 결괏값이 항상 최적의 결괏값이라 볼 수 없다.
따라서 최단 경로를 구하는데 적합하지 못하다. 또한, 모든 노드를 하나하나 탐색해야 하므로,
시간이 상당히 오래 걸린다.
BFS의 경우 위에서 간단하게 한층 한층 탐색하는 방법이라 서술했다.
즉 최단경로를 구하기에 적합하다.
설명을 돕기 위해, 위의 그래프를 다른 각도로 보겠다.
위의 그래프를 살펴보면, 당연히 1에서 가장 먼 노드는 4, 5, 6 노드 3개이다.
1층부터 3층까지 있는 건물에서, 1층을 기준으로 가장 먼 층수는 3층이 되는 것 과 마찬가지다.
따라서 BFS를 사용하여 문제를 해결한다.
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Programmers_Graph_가장먼노드 {
static boolean[] visited;
public int solution(int n, int[][] edge) {
int answer = 0;
this.visited = new boolean[n];
List<List<Integer>> nodeList = setList(n, edge);
Queue<Integer> nodeQue = new LinkedList<>();
nodeQue.offer(0);
this.visited[0] = true;
while(!nodeQue.isEmpty()) {
answer = nodeQue.size();
nodeQue = setQue(nodeQue, nodeList);
}
return answer;
}
public List<List<Integer>> setList (int n, int[][] edge) {
List<List<Integer>> nodeList = new ArrayList<>();
List<Integer> temp;
for(int index = 0, size = n ; index < size ; ++index) {
nodeList.add(new ArrayList<>());
}
for(int index = 0, size = edge.length ; index < size ; ++index) {
int start = edge[index][0] - 1;
int end = edge[index][1] - 1;
temp = nodeList.get(start);
if(!temp.contains(end)) {
temp.add(end);
}
temp = nodeList.get(end);
if(!temp.contains(start)) {
temp.add(start);
}
}
return nodeList;
}
public Queue<Integer> setQue (Queue<Integer> queue, List<List<Integer>> nodeList) {
List<Integer> temp;
Queue<Integer> newQueue = new LinkedList<>();
while(!queue.isEmpty()) {
temp = nodeList.get(queue.poll());
for(int index = 0, size = temp.size() ; index < size ; ++index) {
int nodeLink = temp.get(index);
if(!this.visited[nodeLink]) {
newQueue.offer(nodeLink);
this.visited[nodeLink] = !this.visited[nodeLink];
}
}
}
return newQueue;
}
}
각 노드들에 대해 방문 여부를 판단한다.
각 노드의 번호를 인덱스로 false면 미방문, true면 방문한 것으로 판단한다.
각 노드들에 대한 연결된 노드를 확인하기 위해, 직접적인 그래프를 구현하기보다
List를 통해 간이 그래프를 구성하기 위한 메서드다.
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
class Programmers_Graph_가장먼노드Test {
Programmers_Graph_가장먼노드 main = new Programmers_Graph_가장먼노드();
@Test
void solution() {
int n = 6;
int[][] vertex = {{3, 6}, {4, 3},{3, 2}, {1, 3}, {1, 2}, {2, 4}, {5, 2}};
assertThat(3, is(main.solution(n, vertex)));
n = 4;
int[][] vertex_2 = {{1,2}, {1,3}, {3,4}, {4,2}};
assertThat(1, is(main.solution(n, vertex_2)));
n = 4;
int[][] vertex_3 = {{1,2}, {1,3},
{2,3}, {2,4},
{3,4}};
assertThat(1, is(main.solution(n, vertex_3)));
}
}
BOJ 2839 설탕 배달 (Java) (0) | 2020.04.14 |
---|---|
프로그래머스 단어 변환_Java (DFS & BFS) (0) | 2020.03.26 |
BOJ_BackTracking_15649_N과 M (Java) (0) | 2020.03.09 |
BOJ_Math3_9375_패션 왕 신해빈 (Java) (0) | 2020.02.29 |
BOJ_Reculsive Function_10870_피보나치 수 5 (Java) (0) | 2020.02.27 |