주의사항
- JAVA를 사용하여 프로그램을 사용하였습니다.
- 백준에서 코드를 작성하였을 때 아래 형태에서 Main에서 결과가 출력되어야 합니다.
public class Main{
public static void main(String[] args){
}
}
문제 설명


접근 방법
동적 계획법
모든 연산을 수행하면 똑같은 연산을 중복되게 수행하게 되는데 다이나믹 프로그램은 연산한 내용을 따로 저장하여 효율적으로 작성한 프로그램입니다.
더 자세한 내용은 링크를 남겨두겠습니다.
동적 계획법 - 위키백과, 우리 모두의 백과사전
수학과 컴퓨터 과학, 그리고 경제학에서 동적 계획법(動的計劃法, dynamic programming)이란 복잡한 문제를 간단한 여러 개의 문제로 나누어 푸는 방법을 말한다. 이것은 부분 문제 반복과 최적 부분
최단경로는 시작 정점에서 목표 정점까지 최소의 비용으로 갈 수 있는 경로를 구하는 것입니다.
최단 경로를 구하는 알고리즘은 대표적으로 3개가 존재합니다.
1. 다익스트라 알고리즘
2. 벨만-포드 알고리즘
3. 플로이드 워셜 알고리즘
3가지 알고리즘은 문제를 해결할 때 사용하는 알고리즘만 설명하도록 하겠습니다.
플로이드 워셜 알고리즘이란?
1. 각 정점들을 기준으로 n번을 거쳐서 각 정점들을 도착하는 최단 거리를 구합니다.
2. 이동을 할 때마다 이동한 거리가 현재 저장된 거리보다 작으면 변경합니다.
3. 위 과정을 반복이 끝나면 각 정점에서 다른 정점에 최단 거리를 구할 수 있습니다.
더 자세한 내용은 아래 링크를 통해 확인해주시기 바랍니다.
플로이드-워셜 알고리즘 - 위키백과, 우리 모두의 백과사전
컴퓨터 과학에서, 플로이드-워셜 알고리즘(Floyd-Warshall Algorithm)은 변의 가중치가 음이거나 양인 (음수 사이클은 없는) 가중 그래프에서 최단 경로들을 찾는 알고리즘이다.[1][2] 알
이 문제에 핵심은
1. 한 도시에서 다른 도시로 출발하는 버스이다. = 방향이 있는 간선이다.
2. 버스의 비용은 10만보다 작거나 같은 자연수이다.
3. 출발점에서 각 지점까지 최소비용, 방문 도시 개수, 경로를 출력해야 한다.
4. 출발 도시와 도착 도시도 방문 도시와 경로에 포함된다.
그래프에 대한 내용을 정의하기 위해 ArrayList<ArrayList<Integer>>의 형태로 리스트를 만들어주었습니다.
위와 같이 정의하여 데이터를 저장하면 각 정점이 어떤 정점으로 이동하는지 간단하게 저장할 수 있습니다.
예를 들어
1 -> 4
1 -> 3
2 -> 5
3 -> 4
ArrayList<ArrayList<Integer>>의 저장되는 모습은 리스트 안에 리스트가 포함되는 형식으로 저장됩니다.
| 정점 | ||
| 1 | 3 | 4 |
| 2 | 5 | |
| 3 | 1 | 4 |
| 4 | 1 | 4 |
| 5 | 2 |
그래프의 값을 리스트에 저장하였다면 출발점을 기준으로 for문을 이용하여 플로이드 알고리즘을 구현하였습니다.
플로이드 탐색하는 과정을 살펴보시려면 아래 링크 문제를 풀 때 어떻게 진행되는지 표현한 것을 참고해주시면 감사하겠습니다.
[백준] 단계별로 풀어보기(단계:25, 최단 경로,JAVA)11404번, 플로이드
문제 링크 11404번: 플로이드 첫째 줄에 도시의 개수 n이 주어지고 둘째 줄에는 버스의 개수 m이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그
tussle.tistory.com
이 문제에서는 최단 비용뿐만 아니라 지나가는 도시의 경로를 출력해야 합니다.
버스를 타고 이동할 때 이전 도시에 값들을 저장하는 배열을 만들었습니다.
만약 도시1 -> 도시2로 이동한다면
next[1][2] = 1이 저장되는 형식입니다.
플로이드 알고리즘으로 최단 비용 경로를 구할 때 같이 배열을 구성합니다.
이후 경로를 출력할 때에는 LIFO(후입선출) 형식의 Stack을 이용하여 도착 지점부터 출발지점까지 가는 next에 값들을 역추적하면서 Stack에 도시 번호를 저장합니다.
Stack에 저장된 값들을 출력하여 경로를 표현할 수 있습니다.
Stack에 저장되었던 도시들은 최단 비용으로 갔을 때 들린 도시의 수로 표현할 수 있기 때문에 저장된 수만큼 결과로 출력하면 됩니다.
문제를 해결한 알고리즘의 과정입니다.
1. 입력값을 받아서 저장합니다.
2. 플로이드 알고리즘을 이용하여 각 지점에서 다른 지점에 최소 비용과 이동 경로를 배열에 저장합니다.
3. 최소 비용, 방문 도시 개수, Stack을 이용한 경로를 결과로 출력합니다.
- BufferedReader를 사용하여 입력 값을 받았습니다.
- StringTokenizer를 이용하여 버스의 이동경로를 나누어 graph에 저장하였습니다.
- 플로이드 알고리즘를 이용한 지점에서 다른 지점으로 가는 최단 비용과 경로를 구하는 cal함수를 실행하였습니다.
- BufferedWriter에 최단 비용을 저장하였습니다.
- Stack과 next[]을 이용하여 이동 경로와 방문 도시 개수를 BufferedWriter에 저장하였습니다.
- BufferedWriter에 저장된 결과값을 출력하였습니다.
- cal함수는 플로이드 알고리즘을 이용하여 next와 arr를 구성합니다.
import java.io.*;
import java.util.*;
public class Main {
static int n,m,INF = 10000001;
static int[][] arr,next; //최단 경로, 이전 경로 저장하는 배열
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//입력값 처리하는 BufferedReader
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
//결과값 출력하는 BufferedWriter
Stack<Integer> stack = new Stack<Integer>();
StringTokenizer st;
n = Integer.parseInt(br.readLine());
m = Integer.parseInt(br.readLine());
arr = new int[n+1][n+1];
next = new int[n+1][n+1];
//최단 경로 저장할 배열 초기화
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(i!=j)
arr[i][j] = INF;
}
}
//입력받은 버스 경로 값, 이전 경로값 배열에 저장
for(int i=0;i<m;i++) {
st = new StringTokenizer(br.readLine()," ");
int a = Integer.parseInt(st.nextToken());
int b = Integer.parseInt(st.nextToken());
int c = Integer.parseInt(st.nextToken());
arr[a][b] = Math.min(arr[a][b], c);
next[a][b] = a;
}
cal(); //최단 비용과 경로 구하는 함수 실행
//최단 비용 값들 BufferedWriter 저장
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(arr[i][j] ==INF)
bw.write("0 ");
else
bw.write(arr[i][j] + " ");
}
bw.newLine();
}
//방문 도시 개수와 경로 BufferedWriter 저장
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
if(next[i][j]==0) //해당 도시 도착하지 못할 경우
bw.write("0\n");
else { //해당 도시 도착할 때
int e = j;
stack.add(e);
while(next[i][e] != i) {
stack.add(next[i][e]);
e = next[i][e];
}
bw.write(stack.size() + 1 + " ");
bw.write(i + " ");
while(!stack.isEmpty())
bw.write(stack.pop() + " ");
bw.newLine();
}
}
}
bw.flush(); //결과 출력
bw.close();
br.close();
}
//for문을 이용한 플로이드 알고리즘을 구현한 함수
static void cal() {
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
for(int k=1;k<=n;k++) {
if(arr[j][k] > arr[j][i] + arr[i][k]) {
arr[j][k] = arr[j][i] + arr[i][k]; //최단 비용
next[j][k] = next[i][k]; // 이전 도시
}
}
}
}
return;
}
}
'백준' 카테고리의 다른 글
| [백준] 단계별로 풀어보기(단계:12, 집합과 맵,JAVA)1620번, 나는야 포켓몬 마스터 이다솜 (0) | 2022.05.10 |
|---|---|
| [백준] 단계별로 풀어보기(단계:12, 집합과 맵,JAVA)14425번, 문자열 집합 (0) | 2022.05.10 |
| [백준] code.plus(시뮬레이션과 구현,JAVA)14499번, 주사위 돌리기 (0) | 2022.05.09 |
| [백준] 단계별로 풀어보기(단계:12, 집합과 맵,JAVA)10815번, 숫자 카드 (0) | 2022.05.08 |
| [백준] code.plus(시뮬레이션과 구현,JAVA)16927번, 배열 돌리기 2 (0) | 2022.05.08 |
댓글