다익스트라(Dijkstra)
로 풀어주세요다익스트라만 구현하면 되는 특별할거 없는 문제라서
다익스트라 구현을 설명하는 자료는 레퍼런스로 대체하겠습니다.
https://blog.naver.com/ndb796/221234424646
무한 반복
3번
을 수행하기 위해서 전체 배열을 순회하면 시간 복잡도는 O(N)
이다.
4번
을 수행하기 위해서는 시간 복잡도는 O(N)
이 걸린다.
총 시간 복잡도는 O(N^2)
가 되는데 여기서 더 최적화가 가능하다
3번
을 수행하기 위해서 minHeap
을 사용하는 것이다.
그러면 가장 가까운 노드를 꺼내고 minHeap을 다시 업데이트 하는데 시간복잡도가 O(LogN)
이다.
그러면 종합적으로 시간복잡도는 O(N*LogN)
이 걸린다.
도달 불가능하다는 의미로 INF = Integer.MAX_VALUE
사용함 ⇒ 오버플로우 발생
적당히 큰 값으로 INF
를 수정함 ⇒ 샘플 테케에서 정상 작동
INF
의 기준 = 가중치 최대값(10) * 간선의 최대개수(200,000) + 안전빵(1) ⇒ 도달 불가능
기준 못 찾겠다? ⇒ BruteForce로 테스트해서 찾으세요 ⇒ 이진탐색하면 더 빠르겠다 그쵸
그래프를 인접행렬로 구현해봤다 ⇒ 메모리가 터졌다 ⇒ 그럴리가 256메가라고
메모리 계산 시작
package lecture.d0902;
import java.io.*;
import java.util.*;
public class BOJ_G4_1753_최단경로 {
// 입력고정
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static StringBuilder output = new StringBuilder();
static int V;
static int E;
// 세팅
static boolean[] visit;
static int[] distance;
static int[][] graph;
// static int INF = Integer.MAX_VALUE;
static int INF = 10*200_000+1;
// 메소드
static int getMinNode() {
int min = INF;
int node = 0;
for (int i = 0; i < V; i++) {
if( (distance[i]<min) && (visit[i]==false) ) {
min = distance[i];
node = i;
}
}
return node;
}
//// 다익스트라
static void dijkstra(int start) {
visit = new boolean [V];
visit[start-1] = true;
distance = graph[start-1];
distance[start-1] = 0;
for (int i = 0; i < V; i++) {
int currentNode = getMinNode();
visit[currentNode] = true;
for (int node = 0; node < V; node++) {
if(visit[node]==false) { // 방문이면 이미 최소화 루트를 통해서 결정된 값이기때문에 최소값임. 굳이 갱신할필요가 없음. 갱신하는 로직에 포함시켜도 됨. 어차피 더 작은 값이 안 붙어서 갱신안됨.
if(distance[currentNode] + graph[currentNode][node] < distance[node]) {
distance[node] = distance[currentNode] + graph[currentNode][node];
}
}
}
}
}
// 메인
public static void main(String[] args) throws NumberFormatException, IOException {
// 입력
tokens = new StringTokenizer(input.readLine());
V = Integer.parseInt(tokens.nextToken());
E = Integer.parseInt(tokens.nextToken());
int start = Integer.parseInt(input.readLine());
graph = new int[V][V];
for (int i = 0; i < graph.length; i++) {
Arrays.fill(graph[i], INF);
}
// System.out.println(Arrays.deepToString(graph));
// System.out.println("=============");
for (int i = 0; i < E; i++) {
tokens = new StringTokenizer(input.readLine());
int row = Integer.parseInt(tokens.nextToken())-1; // -1 해서 그래프에 맞게 넣음.
int col = Integer.parseInt(tokens.nextToken())-1; // -1
int weight = Integer.parseInt(tokens.nextToken());
int value = graph[row][col];
graph[row][col] = Math.min(value, weight); // 최소값 업데이트
}
// for (int i = 0; i < graph.length; i++) {
// System.out.println(Arrays.toString(graph[i]));
// }
// 세팅
// visit = new boolean[V];
// distance = new int[V];
// Arrays.fill(distance, INF);
// 작업
dijkstra(start);
// 출력
for (int i = 0; i < V; i++) {
if(distance[i]==INF) {
output.append("INF").append("\n");
} else {
output.append(distance[i]).append("\n");
}
}
System.out.println(output);
}
}
인접 행렬을 인접 리스트로 바꾼다 ⇒ 관련 로직 수정 ⇒ 성공 ⇒ 나이브로도 충분
바뀐 부분
최소 가중치 간선 갱신 로직과 코드
dijkstra 돌때 참조하는 코드
package lecture.d0902;
// 인접 리스트로...
import java.io.*;
import java.util.*;
public class BOJ_G4_1753_최단경로2 {
// 입력고정
static BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer tokens;
static StringBuilder output = new StringBuilder();
static int V;
static int E;
// 세팅
static boolean[] visit;
static int[] distance;
static ArrayList<int[]>[] graph; // int[]을 담는 ArrayList의 배열 ㅋㅋ..
static int INF = 10*200_000+1;
// 메소드
static int getMinNode() {
int min = INF;
int node = 0;
for (int i = 0; i < V; i++) {
if( (distance[i]<min) && (visit[i]==false) ) {
min = distance[i];
node = i;
}
}
return node;
}
//// 다익스트라
static void dijkstra(int start) {
// 부품 초기화 1
visit = new boolean [V];
visit[start-1] = true;
distance = new int [V];
Arrays.fill(distance, INF);
// 부품 초기화 2
distance[start-1] = 0;
for (int i = 0; i < graph[start-1].size(); i++) { // 어레이 리스트 순회
int node = graph[start-1].get(i)[0];
int weight = graph[start-1].get(i)[1];
distance[node] = weight;
}
for (int i = 0; i < V; i++) {
int currentNode = getMinNode();
visit[currentNode] = true;
for (int node = 0; node < graph[currentNode].size(); node++) {
int nextNode = graph[currentNode].get(node)[0];
int nextWeight = graph[currentNode].get(node)[1];
if(visit[nextNode] == false) { // 방문이면 이미 최소화 루트를 통해서 결정된 값이기때문에 최소값임. 굳이 갱신할필요가 없음. 갱신하는 로직에 포함시켜도 됨. 어차피 더 작은 값이 안 붙어서 갱신안됨.
if(distance[currentNode] + nextWeight < distance[nextNode]) {
distance[nextNode] = distance[currentNode] + nextWeight;
}
}
}
}
}
// 메인
public static void main(String[] args) throws NumberFormatException, IOException {
// 입력
tokens = new StringTokenizer(input.readLine());
V = Integer.parseInt(tokens.nextToken());
E = Integer.parseInt(tokens.nextToken());
int start = Integer.parseInt(input.readLine());
graph = new ArrayList[V];
for (int i = 0; i < V; i++) {
graph[i] = new ArrayList<>();
}
for (int i = 0; i < E; i++) {
tokens = new StringTokenizer(input.readLine());
int row = Integer.parseInt(tokens.nextToken())-1; // -1 해서 그래프에 맞게 넣음.
int col = Integer.parseInt(tokens.nextToken())-1; // -1
int weight = Integer.parseInt(tokens.nextToken());
// 인접리스트 생성 + 업데이트
boolean isAlready = false;
for (int j = 0; j < graph[row].size(); j++) {
int alreadyNode = graph[row].get(j)[0];
int alreadyWeight = graph[row].get(j)[1];
if(alreadyNode==col) { // 같은 노드를 잇는 간선이 기존에 있음 => 최소값만 남김.
graph[row].get(j)[1] = Math.min(weight, alreadyWeight);
isAlready = true;
break;
}
}
if(isAlready==false) { // 기존에 없다고? 추가해~
graph[row].add(new int[] {col,weight});
}
}
// for (int i = 0; i < graph.length; i++) {
// System.out.println(Arrays.toString(graph[i]));
// }
// 세팅
// 작업
dijkstra(start);
// 출력
for (int i = 0; i < V; i++) {
if(distance[i]==INF) {
output.append("INF").append("\n");
} else {
output.append(distance[i]).append("\n");
}
}
System.out.println(output);
}
}
간선이 풀로 있는 완전그래프면 방문을 모두 끝마쳤을때 탈출하는게 바람직해보임
minHeap을 안쓰는 나이브한 방법에서는 최소값을 유지해줘야 했지만,
minHeap을 쓰면 어차피 최소값인 간선만 타게 되니까 그래프를 표현할때 최소값을 쓸 필요가 없다.
정성스러운 포스팅 잘보고 가용!
이제 날씨가 많이 풀렸는데 따뜻한 봄햇살을 맞으시면서 오늘도 내일도 매일매일 행복한 하루를 보내시길 바래용!
가끔씩 시간 나시면 제 블로그도 한번씩 들려주시면 감사하겠습니다 ^^ ♥
자주 놀러올께욧!