🙇‍♀️원더랜드(Kruskal MST 알고리즘 : Union&Find 활용)

원더랜드에 문제가 생겼다.

원더랜드의 각 도로를 유지보수하는 재정이 바닥난 것이다.

원더랜드는 모든 도시를 서로 연결하면서 최소의 유지비용이 들도록 도로를 선택하고 나머지 도로는 폐쇄하려고 한다.

어떤 도로는 도로를 유지보수하면 재정에 도움이 되는 도로도 존재한다.

재정에 도움이 되는 도로는 비용을 음수로 표현했다.

아래의 그림은 그 한 예를 설명하는 그림이다.

원더 랜드

위의 지도는 각 도시가 1부터 9로 표현되었고, 지도의 오른쪽은 최소비용 196으로 모든 도시를 연결하는 방법을 찾아낸 것이다.

▣ 입력설명
첫째 줄에 도시의 개수 V(1≤V≤100)와 도로의 개수 E(1≤E≤1,000)가 주어진다. 

다음 E개의 줄에는 각 도로에 대한 정보를 나타내는 세 정수 A, B, C가 주어진다. 

이는 A번 도시와 B번 도시가 유지비용이 C인 도로로 연결되어 있다는 의미이다. 

C는 음수일 수도 있으며, 절댓값이 1,000,000을 넘지 않는다.

▣ 출력설명
모든 도시를 연결하면서 드는 최소비용을 출려한다.

▣ 입력예제 1 
9 12
1 2 12
1 9 25
2 3 10
2 8 17
2 9 8
3 4 18
3 7 55
4 5 44
5 6 60
5 7 38
7 8 35
8 9 15

▣ 출력예제 1
196

🚀풀이

비용이 최소인것 부터 정렬을하고 그래프에 포함시키기 시작한다.

간선을 넣을 때 사이클이 생긴다면 포함시키지 않는다.

Union&Find구조에서 같은 집합이라면 사이클이 생기는 경우이다.
그래서 같은 집합이 아닐때 집어놓고 같은 집합으로 만든다.

🚀전체 코드

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include<iostream>
#include <fstream>
#include <vector>
#include <algorithm>

using namespace std;

struct Edge
{
	int a, b, val;

	bool operator<(const Edge& other) const
	{
		return val < other.val;
	}
};

int n, m, a, b, val, res = 0;
int unf[101];
vector<Edge> edges;

int Find(int v)
{
	if (v == unf[v])
		return v;
	else
		return unf[v] = Find(unf[v]);
}

void Union(int a, int b)
{
	a = Find(a);
	b = Find(b);
	if (a != b)
		unf[a] = b;
}

void solve()
{
	cin >> n >> m;
	// 독립적인 집합 생성
	for (int i = 1; i <= n; ++i)
		unf[i] = i;

	// 간선 정보 기입
	for (int i = 1; i <= m; ++i)
	{
		cin >> a >> b >> val;
		edges.push_back({ a, b, val });
	}

	// 비용이 낮은순으로 정렬
	sort(edges.begin(), edges.end());

	for (int i = 0; i < m; ++i)
	{
		int fa = Find(edges[i].a);
		int fb = Find(edges[i].b);
		if (fa != fb)
		{
			res += edges[i].val;
			Union(edges[i].a, edges[i].b);
		}
	}

	cout << res;
}

int main() 
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	freopen("input.txt", "rt", stdin);

	solve();

	return 0;
}