Algorithm

[백준 13905] 세부

Mirab 2021. 11. 20. 23:48
문제 풀이

 

숭이는 혜빈이를 위해서 금 빼빼로를 최대한으로 들고 가고 싶어 합니다.

그런데 금 빼빼로를 혜빈이까지 옮기기 위해서는 그만큼의 무게를 견디는 다리가 있어야 하는데요.

어떻게 하면 숭이가 혜빈이까지 움직일 수 있는지 구하는 게 이번 문제입니다.

 

우선은 최대한 금 빼빼로를 가져다가 주면 좋아하기 때문에, 최대한으로 설정해놓고 움직일 수 있도록 다리를 만들어야 합니다. 기존에 MST를 이용해서 어떻게 하면 최소한의 비용으로 모든 도시들을 연결한 방법이 있었는데, 이것을 반대로 생각해서 최대한의 비용으로 모든 도시들을 연결하게 설정합니다.

왜냐하면 우리는 금 빼빼로를 최대한으로 들고 가야하기 때문입니다.

 

최대한의 비용으로 그래프를 설계했다면 아래와 같을 것입니다.

노란색으로 색칠한 부분이 우리가 만든 최대의 비용으로 만든 그래프입니다.

이때 숭이가 1번 집에 있고, 혜빈이가 5번 도시에 있을 때 어떻게 하면 최대한 많은 금 빼빼로를 혜빈이에게 줄 수 있을까요?

 

우선은 혜빈이에게 갈려면 빨간색 선으로 되어있는 것처럼 7번 집, 6번 집, 5번 집을 거쳐가야 할 겁니다.

7번 집의 다리 내구도를 보니까 4까지 견딜 수 있고,

6번 집의 다리 내구도를 보니까 4까지 견딜 수 있고,

5번 집의 다리 내구도를 보니까 3까지 견딜 수 있네요.

즉 최대한 많은 금 빼빼로는 총 3개만 가져갈 수 있다는 것을 알았습니다.

4개를 가져가게 되면 6번 집에서 5번 집으로 갈 때 무너지겠죠.

 

어떻게 하면 이렇게 계산할 수 있을까요?

아까 위에서 우리는 MST를 최대 비용으로 집들을 연결했습니다.

1, 7을 연결할 때 두 집을 연결하는 과정에서 우리는 따로 인접 리스트 그래프를 한 개 더 만듭니다.

이 그래프는 얼마큼 금 빼빼로를 가져갈지 계산하기 위해서입니다.

 

그래서 두 그래프를 연결할 때마다 인접 리스트로 두 집의 양방향 연결을 만들어주고,

숭이 내 집에서 혜빈이 집까지 최소한의 비용으로 확인하면서 찾아가면 문제를 해결할 수 있습니다.

 

모든 집 들을 다리로는 나올 수 없는 987654321(무한대)형태로 초기화시킨 후,

숭이 내 집에서 출발해서 인접한 모든 집들을 확인하면서 더 싼 비용으로 갱신해나가면 됩니다.

이렇게 갱신해나가면 위의 빨간색 선분 처럼 우리는 1번 집에서 5번 집으로 갈 때 min(4, 4, 3)을 만나 결국 3이라는 값을 도출할 수 있습니다.

 

소스 코드
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;

const int MAX = 100001;
const int INF = 987654321;

int N, M, s, e;
vector<pair<int, pair<int, int> > > edges;
int parent[MAX];

vector<pair<int, int> > adj[MAX];
bool visit[MAX];
int dist[MAX];

bool compare(const pair<int, pair<int, int> >&  a, const pair<int, pair<int, int> >&  b)
{
	return a.first > b.first;
}

int findParent(int x)
{
	if (x == parent[x]) return x;
	return parent[x] = findParent(parent[x]);
}

void unionParent(int a, int b)
{
	a = findParent(a);
	b = findParent(b);
	if (a < b) parent[b] = a;
	else parent[a] = b;
}

void input()
{
	cin >> N >> M >> s >> e;
	for (int i = 0; i < M; i++)
	{
		int h1, h2, k;
		cin >> h1 >> h2 >> k;
		edges.push_back({ k, {h1,h2} });
	}
}

void kruskal()
{
	sort(edges.begin(), edges.end(), compare);
	for (int i = 1; i <= N; i++) parent[i] = i;

	int sz = static_cast<int>(edges.size());
	vector<int> ans;
	for (int i = 0; i < sz; i++)
	{
		int cost = edges[i].first;
		int a = edges[i].second.first;
		int b = edges[i].second.second;
		if (findParent(a) != findParent(b))
		{
			unionParent(a, b);
			adj[a].emplace_back(b, cost);
			adj[b].emplace_back(a, cost);
		}
	}
}

void dijkstra()
{
	fill(dist, dist + MAX, INF);

	queue<int> q;
	q.push(s);
	visit[s] = true;
	while (!q.empty())
	{
		int cur = q.front();
		q.pop();

		for (int i = 0; i < adj[cur].size(); i++)
		{
			int next = adj[cur][i].first;
			int nextDistance = adj[cur][i].second;

			if (visit[next]) continue;
			visit[next] = true;
			// 핵심: 금빼빼로를 최대한으로 들고가려고 할 때 그 무게를 견딜 수 있는 걸 찾아야하기 때문에
			// 최소한 무게를 버틸 수 있도록 다리의 무게제한을 갱신한다.
			dist[next] = min(dist[cur], nextDistance);
			q.push(next);
		}
	}

	// 중요한 점은 못갈 수 있다는 것
	if (dist[e] == INF)
		cout << "0\n";
	else
		cout << dist[e] << endl;
}

void solve()
{
	input();
	kruskal();
	dijkstra();
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	solve();
	return 0;
}

'Algorithm' 카테고리의 다른 글

[백준 16398] 행성 연결  (0) 2021.11.22
[백준 16202] MST 게임  (0) 2021.11.21
[백준 6497] 전력난  (0) 2021.11.19
[백준 4386] 별자리 만들기  (0) 2021.11.19
[백준 1922] 네트워크 연결  (0) 2021.11.19