본문 바로가기
알고리즘 문제 풀이/백준

백준 1719 택배 c++ (플로이드 와샬)

by 옹구스투스 2021. 8. 8.
반응형

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

 

1719번: 택배

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

www.acmicpc.net

문제

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

예시된 그래프에서 굵게 표시된 1, 2, 3, 4, 5, 6은 집하장을 나타낸다. 정점간의 간선은 두 집하장간에 화물 이동이 가능함을 나타내며, 가중치는 이동에 걸리는 시간이다. 이로부터 얻어내야 하는 경로표는 다음과 같다.

경로표는 한 집하장에서 다른 집하장으로 최단경로로 화물을 이동시키기 위해 가장 먼저 거쳐야 하는 집하장을 나타낸 것이다. 예를 들어 4행 5열의 6은 4번 집하장에서 5번 집하장으로 최단 경로를 통해 가기 위해서는 제일 먼저 6번 집하장으로 이동해야 한다는 의미이다.

이와 같은 경로표를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 두 수 n과 m이 빈 칸을 사이에 두고 순서대로 주어진다. n은 집하장의 개수로 200이하의 자연수, m은 집하장간 경로의 개수로 10000이하의 자연수이다. 이어서 한 줄에 하나씩 집하장간 경로가 주어지는데, 두 집하장의 번호와 그 사이를 오가는데 필요한 시간이 순서대로 주어진다. 집하장의 번호들과 경로의 소요시간은 모두 1000이하의 자연수이다.

출력

예시된 것과 같은 형식의 경로표를 출력한다.

알고리즘 분류

풀이

모든 정점에서 모든 정점에 가는 최단 경로를 구하는 플로이드 와샬 문제이다.

이 문제에선 최단 경로를 구하는 것이 아니라 최단 경로 중 최초로 거치는 노드를 구하는 문제이다.

1행 6열을 보면 1에서 6을 가려면 1 -> 2 -> 5 -> 6 순으로 방문하는데,

최초로 거치는 노드는 2이므로 답은 2이다.

1행 2열을 보면 1에서 2를 가려면 1 -> 2

최초로 거치는 노드는 2이므로 답은 2이다.

 

답(최초로 거치는 노드)을 저장하는 배열 answer[][]과, 증가치를 저장하는 graph[][]가 있다고 하자.

 

플로이드 와샬 알고리즘의 로직에 따라

graph에서 본인이 본인 노드를 향할 땐 0,

다른 노드를 향할 땐 INF로 초기화하고, 

간선을 입력받아 한 번에 갈 수 있는 노드는 증가치를 저장해 준다.

answer의 초기값은 모두 0이고, 간선을 입력받았을 때,

a->b로 한 번에 갈 수 있는 노드는 answer[a][b] =b를 저장해 준다. 

//a행 b열이기 때문에 a->b이고 이때 답은 b다

 

이후 i에서 j를 갈 때 모든 k를 거쳐 가는 경우 중에서 최솟값을 그래프에 저장해 최단 경로를 갱신하면서,

answer[i][j]에는 answer[i][k]값을 저장한다.

//i에서 j로 갈 때, i에서 k를 거쳐서 j로 가는 것이 더 짧은 경로라면 i에서 k를 가는 데 최초로 거치는 노드가

  i에서 j로 가는 데의 최초로 거치는 노드가 된다.

i=1

j=6

k=5

1 -> 2 -> 5 -> 6

answer[1][5] = 2

answer[1][6] = answer[1][5] = 2

코드

#include <iostream>
#include <algorithm>

#define MAX (201)
#define INF (987654321)

using namespace std;

int N, M;

int graph[MAX][MAX], answer[MAX][MAX];

int main() {

	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> N >> M;
	
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N; j++) {
			if (i == j)
				graph[i][j] = 0;
			else
				graph[i][j] = INF;
		}
	}

	for (int i = 0; i < M; i++) {
		int from, to, dis;
		cin >> from >> to>>dis;
		graph[from][to] = dis;
		graph[to][from] = dis;
		answer[from][to] = to;
		answer[to][from] = from;
	}

	for (int k = 1; k <= N; k++) {
		for (int i = 1; i <= N; i++) {
			for (int j = 1; j <= N; j++) {
				if (graph[i][j] > graph[i][k] + graph[k][j]) {
					graph[i][j] = graph[i][k] + graph[k][j];
					answer[i][j] = answer[i][k];
				}
			}
		}
	}
	for (int i = 1; i <= N; i++) {
		for (int j = 1; j <= N;j++) {
			if (answer[i][j] == 0)
				cout << "- ";
			else
			cout << answer[i][j]<< ' ' ;
		}
		cout << '\n';
	}

	return 0;
}
반응형

댓글