알고리즘

BOJ 13418: 학교 탐방하기

minbear 2023. 7. 26. 16:55

#BOJ 13418: 학교 탐방하기

 

13418번: 학교 탐방하기

입력 데이터는 표준 입력을 사용한다. 입력은 1개의 테스트 데이터로 구성된다. 입력의 첫 번째 줄에는 건물의 개수 N(1 ≤ N ≤ 1,000)과 도로의 개수 M(1 ≤ M ≤ N(N-1)/2) 이 주어진다. 입력의 두 번

www.acmicpc.net

#풀이

학교 지도를 보면 연결 그래프인 걸 알 수 있다. 또한 문제를 읽다보면 최소 신장 트리 인 것을 알 수 있다.

 

나는 문제를 잘못읽어서 입구는 무조건 간선이 1번과의 간선만 있는 줄 알고 풀었다가 틀렸다..

 

일단 이 문제는 간단하다.

 

가중치를 내림차순으로 정렬하여 최대 신장 트리를 구하고

가중치를 오름차순으로 정렬하여 최소 신장 트리를 구한 다음

 

피로도를 빼면 구할 수 있다.

 

#코드

#include<bits/stdc++.h>

using namespace std;
int n, m;
long long max_ans = 0;
long long min_ans = 0;
vector<tuple<int,int,int>> road;
vector<int> p(1001, -1);

int find(int x){
	if(p[x] < 0) return x;
	return p[x] = find(p[x]);
}
bool is_diff(int a, int b){
	int u, v;
	u = find(a); 
	v = find(b);
	if(u==v) return 0;
	if(u<=v) p[v]=u;
	else p[u]=v;
	return 1;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	int a, b, w;
	
	for(int i = 0; i <=m; i++){
		cin >>a >> b>> w;
		road.push_back({w,a,b});
	}
	sort(road.begin(), road.end());
	int cnt = 0;
	for(auto nxt : road){ // 최악의 경우
		int w, a, b;
		tie(w, a, b) = nxt;
		if(!is_diff(a,b)) continue;
		
		if(w == 0) max_ans++;
		
		cnt++;
		if(cnt == n) break;
	}

	p = vector<int>(1001,-1);
	cnt=0;
	for(int i = road.size()-1; i>=0; i--){ // 최선의 경우
		int w, a, b;
		tie(w, a, b) = road[i];
		if(!is_diff(a,b)) continue;
		
		if(!w) min_ans++;
		
		cnt++;
		if(cnt == n) break;
	}
	
	cout << max_ans * max_ans - min_ans*min_ans << '\n';
	return 0;
}
//오르막기 점선 제곱, 내리막길 실선