2 분 소요

플로이드 2 (백준 Gold 2)

https://www.acmicpc.net/problem/11780

n개의 도시와 m개의 도시에 도착하는 버스가 있다

  • 각각의 버스는 시작 도시, 도착 도시, 비용이 존재

모든 쌍 (A,B)에 대하여
A->B의 최소 비용을 출력하고
그 경로를 출력하는 문제

  • 다만 도착할 수 없다면 0 출력

풀이 방법

이전에 보았던 플로이드-워셜 문제와 유사하다

유의사항

  • 각각의 버스는 ‘단방향’!
    또한 비용만 다른 중복 경로 존재하므로
    최단 경로만을 받아서 정리

풀이법

  • maps[i][j].first : i->j로 최단거리로 가기 위해 방문해야 하는 경로 저장
    (이전에 풀었던 것도 사실 i->j를 방문하기 위해 방문해야 하는 것)

  • 그렇다면 maps[i][j].first를 next라 칭했을때
    maps[next][j].first 를 타고 가는 방식으로
    i->j 의 경로를 구할 수 있다!
    (반대로 next가 ‘제자리’에서 돈다면 찾을수 없다는 반증)

  • 그렇기에
    해당 경로를 ‘방문’하면서 목적지에 도달하는지를 체크하는 함수를 만들어
    경로를 반환하였다

제출 코드

#include<iostream>
#include<vector>
#include<unordered_map>

using namespace std;

typedef pair<int, int> pii;

vector<int> getPath(vector<vector<pii>>& maps, int start, int end)
{
	vector<int> result;
	result.push_back(start);

	int next = maps[start][end].first;

	bool bFind = true;

	while (next != end)
	{
		result.push_back(next);

		if (next == maps[next][end].first)
		{
			bFind = false;
			break;
		}
		next = maps[next][end].first;
	}

	result.push_back(end);

	if (bFind == false)
		result.clear();

	return result;
}

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n, m;
	cin >> n >> m;

	const int vv = 1e9;

	vector<vector<pii>> maps(n + 1, vector<pii>(n + 1, { 0,vv }));

	for (int i = 0; i <= n; i++)
	{
		maps[i][i].first = i;
		maps[i][i].second = 0;
	}

	for (int i = 0; i < m; i++)
	{
		int a, b, c;
		cin >> a >> b >> c;

		if (maps[a][b].second > c)
		{
			maps[a][b].first = b;
			maps[a][b].second = c;
		}
	}

	for (int k = 1; k <= n; k++)
	{
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= n; j++)
			{
				if (maps[i][j].second > maps[i][k].second + maps[k][j].second)
				{
					maps[i][j].first = maps[i][k].first;
					maps[i][j].second = maps[i][k].second + maps[k][j].second;
				}
			}
		}
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (maps[i][j].second == vv)
			{
				cout << 0 << ' ';
			}
			else
			{
				cout << maps[i][j].second << ' ';
			}
		}
		cout << '\n';
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (i == j)
			{
				cout << 0 << '\n';
				continue;
			}

			vector<int> r = getPath(maps, i, j);

			cout << r.size() << ' ';
			for (int p : r)
			{
				cout << p << ' ';
			}
			cout << '\n';
		}
	}

	return 0;
}

결과

Image

처음에는 first에 다른 조건을 넣어야 할지
고민했으나 이전의 방식을 응용하면 풀 수 있단걸 알았다

댓글남기기