백준

[백준 10423] 전기가 부족해 (C++)

케굴 2021. 10. 1. 16:53
#include <bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define INF 987654321
using namespace std;
//루트 노드를 찾아주는 코드
typedef pair <int, float>pii;


vector<int> city;
vector <int> gen; //발전기 있는 도시 
int parent[5052];
int N,M,K; 

struct st {
	int s, e;
	float c;
};
//간선간의 cost를 저장해 주자.
st arr[100001];

bool compare(st a, st b) {
	return a.c < b.c;
}

int find(int a) {
	//cout << "find a =" << a<<"\n";
	//a가 root임
	if (parent[a] < 0) return a;
	//a가 root가 아닐때 
	return parent[a] = find(parent[a]);
}

int merge(int a, int b) {
	//cout << "merge a=" << a << " b =" << b << "\n";
	bool connect_a =false, connect_b = false;
	a = find(a);
	b = find(b);
	//cout << "merge a.patent=" << a << " b.parent =" << b << "\n";
	if (a == b)return 0;
	//발전소가 parnet 이면 pass 하자 .ㅇㄸ ? 
	for (int i = 0; i < K ; i++) {
		//cout << "gem[" << i << "] =" << gen[i] << "\n";
		if (a == gen[i])
			connect_a = true;
		if (b == gen[i])
			connect_b = true;	
	}
	if (connect_a == true && connect_b == true)
		return 0;

	//small to large
	if (connect_a == true) {
		parent[a] += parent[b];
		parent[b] = a;
		return 1;
	}
	if (connect_b == true) {
		parent[b] += parent[a];
		parent[a] = b;
		return 1;
	}
	if (parent[a] > parent[b]) swap(a, b);
	parent[a] += parent[b];
	parent[b] = a;
	return 1;
}

void slove() {
	//간선이 작은 순으로 정렬
	sort(arr, arr + M, compare);
	float ans = 0;
	for (int i = 1; i <= N; i++) parent[i] = -1;

	for (int i = 0; i < M; i++) {
		if (merge(arr[i].s, arr[i].e)) {
			ans += arr[i].c;
		}
	}
	cout << ans ;
}


int main() {
	FASTIO;
	int a, b, c;
	cin >> N >> M >>K;
	//cout << N << M << K<<"\n";
	for (int i = 0; i < K; i++) {
		//K개의 발전기 도시 입력 받기 
		cin >> a; 
		gen.push_back(a);
	}
	for (int i = 0; i < M; i++) {
		// 도시간의 cost 입력받기
		cin >> a >> b >> c;
		arr[i].s = a; arr[i].e = b; arr[i].c = c;
	}

	slove();
}

union find를 이용한 크루스칼 알고리즘을 이용해 mst 를 만드는것을 응용해서 풀리는 문제이다.

 

응용해야 하는 부분은 , merge 함수 부분이다. 

merge 해야하는 두 노드의 parent가 발전소라면, 두 노드는 더이상 merge 하지 않는다.

 

그리고 merge 할 때 하나의 노드가발전기라면 , 그 노드에 merge 해 준다.

 

두 노드 모두 발전기가 아니라면 두 그냥 더 큰 노드를 parent로 설정해 준다. 

int merge(int a, int b) {
	//cout << "merge a=" << a << " b =" << b << "\n";
	bool connect_a =false, connect_b = false;
	a = find(a);
	b = find(b);
	//cout << "merge a.patent=" << a << " b.parent =" << b << "\n";
	if (a == b)return 0;
	//발전소가 parnet 이면 pass 하자 . 
	for (int i = 0; i < K ; i++) {
		//cout << "gem[" << i << "] =" << gen[i] << "\n";
		if (a == gen[i])
			connect_a = true;
		if (b == gen[i])
			connect_b = true;	
	}
	if (connect_a == true && connect_b == true)
		return 0;

	//small to large
	if (connect_a == true) {
		parent[a] += parent[b];
		parent[b] = a;
		return 1;
	}
	if (connect_b == true) {
		parent[b] += parent[a];
		parent[a] = b;
		return 1;
	}
	if (parent[a] > parent[b]) swap(a, b);
	parent[a] += parent[b];
	parent[b] = a;
	return 1;
}