본문 바로가기

알고리즘/백준

[JAVA]백준_1719_택배

문제 : https://www.acmicpc.net/problem/1719

 

1719번: 택배

명우기업은 2008년부터 택배 사업을 새로이 시작하기로 하였다. 우선 택배 화물을 모아서 처리하는 집하장을 몇 개 마련했지만, 택배 화물이 각 집하장들 사이를 오갈 때 어떤 경로를 거쳐야 하��

www.acmicpc.net

문제 유형 : 다익스트라, 그래프 이론

 

풀이 방식 

(1) 다익스트라는 한 정점에서 다른 모든 정점을 찾을 때 사용

     => 최단 경로의 최근 노드를 저장하여 dfs로 제일먼저 가야할 노드를 찾음

(2) 플로이드 와샬은 모든 최단 경로를 구하는 방법에 사용됨 

     => 최근 노드를 저장. 양방향 그래프이므로 최근경로를 거꾸로 뒤집으면 처음 가야할 노드를 찾을 수있음

 

소스코드1 (다익스트라)

package BOJ;

import java.io.*;
import java.util.*;

// 다익스트라
public class BOJ_1719_택배_Main {

	private static int[] path;
	private static int[] value;
	private static List<int[]>[] list;
	private static StringBuilder sb;
	private static boolean[] visited;
	private static int n;
	
	public static void main(String[] args) throws IOException {
		// 1. 입력
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine()," ");
		n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken()); // 집하장간 경로의 개수
		list = new ArrayList[n+1];
		for (int i = 1; i < n+1; i++) {
			list[i] = new ArrayList<int[]>();
		}
		
		// 2. 구현
		// 2-1. 인접 리스트
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int from = Integer.parseInt(st.nextToken());
			int to = Integer.parseInt(st.nextToken());
			int val = Integer.parseInt(st.nextToken());
			list[from].add(new int[] {to, val});
			list[to].add(new int[] {from, val});
		}
		
		// 2-2. 다익스트라
		sb = new StringBuilder();
		for (int i = 1; i < n+1; i++) {
			path = new int[n+1];
			value = new int[n+1];
			visited = new boolean[n+1];
			Arrays.fill(value, Integer.MAX_VALUE);
			dijkstra(i);
		}
		System.out.println(sb.toString());
	}

	private static void dijkstra(int num) {
		int start = num;
		value[num] = 0;
		PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				return o1[1]-o2[1];
			}
		});
		pq.offer(new int[] {start, 0});
		while(!pq.isEmpty()) {
			int[] cur = pq.poll();
			int cur_num = cur[0];
			if(!visited[cur_num]) {
				visited[cur_num] = true;
				for (int i = 0; i < list[cur_num].size(); i++) {
					int[] next = list[cur_num].get(i);
					int next_num = next[0];
					int next_val = next[1];
					if(value[next_num]>value[cur_num]+next_val) {
						path[next_num] = cur_num;
						value[next_num] = value[cur_num]+next_val;
						pq.offer(new int[] {next_num, value[next_num],next_num});
					}
				}
			}
		}
		
		// 2-3. dfs로 추적하기
		for (int i = 1; i < n+1; i++) {
			if(i==num) sb.append("- ");
			else {
				int ans = find(i, num);
				sb.append(ans+" ");
			}
		}
		sb.append("\n");
	}

	private static int find(int i, int start) {
		if(path[i] == start) return i;
		return find(path[i], start);
	}

	
}

 

소스코드2 (플로이드와샬)

package BOJ;

import java.io.*;
import java.util.*;

// 플로이드 와샬
public class BOJ_1719_택배_Main2 {

	public static void main(String[] args) throws IOException {
		// 1. 입력
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine()," ");
		int n = Integer.parseInt(st.nextToken());
		int m = Integer.parseInt(st.nextToken()); // 집하장간 경로의 개수
		int[][] matrix = new int[n+1][n+1];
		int[][] path = new int[n+1][n+1];
		for (int i = 1; i < n+1; i++) {
			Arrays.fill(matrix[i], 10001);
			matrix[i][i]=0;
		}
		
		// 2. 구현
		// 2-1. 인접 행렬
		for (int i = 0; i < m; i++) {
			st = new StringTokenizer(br.readLine());
			int from = Integer.parseInt(st.nextToken());
			int to = Integer.parseInt(st.nextToken());
			int val = Integer.parseInt(st.nextToken());
			
			matrix[to][from] = val;
			matrix[from][to] = val;
			
			path[from][to] = from;
			path[to][from] = to;
		}
		
		// 2-2. 플로이드 와샬
		for (int k = 1; k < n+1; k++) {         // 경로
			for (int i = 1; i < n+1; i++) {     // 출발
				for (int j = 1; j < n+1; j++) { // 도착
					if(matrix[i][j]>matrix[i][k]+matrix[k][j]) {
						matrix[i][j] = matrix[i][k] + matrix[k][j]; // 최단 경로 갱신
						path[i][j] = path[k][j]; // i에서 j까지 => k를 지나 j까지
					}
				}
			}
		}

		StringBuilder sb = new StringBuilder();
		for (int i = 1; i < n+1; i++) {
			for (int j = 1; j < n+1; j++) {
				if(i==j) sb.append("- ");
				else sb.append(path[j][i]+" ");
			}sb.append("\n");
		}
		
		System.out.println(sb.toString());
	}

}

'알고리즘 > 백준' 카테고리의 다른 글

[JAVA]백준_18511_큰 수 구성하기  (0) 2020.08.14
[JAVA]백준_2346_풍선터뜨리기  (0) 2020.08.14
[JAVA]백준_10836_여왕벌  (0) 2020.08.12
[JAVA]백준_10282_해킹  (0) 2020.08.12
[JAVA]백준_1713_후보추천하기  (0) 2020.08.07