1. 程式人生 > 其它 >[HNOI2006]公路修建問題

[HNOI2006]公路修建問題

一、題目

HNOI2006

二、思路

這題主要考察的是對kruskal的應用
大概題意就是要連線至少k條一級公路,因為一級公路的花費一定比二級公路多,所以我們可以先連線k條一級公路,然後剩下的全連二級公路。
具體連法就是先對所有路按一級公路花費來排序,這樣能保證連線到的一級公路花費最大的一定是最小的,然後做一遍kruskal
再對二級公路進行排序,將剩下的點用二級公路來連,這樣連線到的二級公路花費最大的一定也是最小的,然後做一遍kruskal
在連線公路的時候對ans取max即可獲得最終答案

三、程式碼

#include<bits/stdc++.h>
using namespace std;
int n, k, m;
struct Edge{
	int a, b, cost1, cost2;
}edges[20020];
int ans = 0;
int s[20020];
void init(){
	for(int i = 0; i <= n; i ++){
		s[i] = i;
	}
}
int find(int x){
	if(s[x] != x) return find(s[x]);
	return x;
}
bool merge(int x, int y){
	x = find(x), y = find(y);
	if(x == y) return false;
	s[x] = y;
	return true;
}
bool cmp1(Edge & e1, Edge & e2){
	return e1.cost1 < e2.cost1;
}
bool cmp2(Edge & e1, Edge & e2){
	return e1.cost2 < e2.cost2;
}
void kruskal1(){
	sort(edges + 1, edges + m, cmp1);
	for(int i = 1; i < m && k; i ++){ //這裡要注意連線k條一級公路,要多加個k的限制範圍
		if(merge(edges[i].a, edges[i].b)){
			ans = max(ans, edges[i].cost1), k --;
		}
	}
}
void kruskal2(){
	sort(edges + 1, edges + m, cmp2);
	for(int i = 1; i < m; i ++){
		if(merge(edges[i].a, edges[i].b)){
			ans = max(ans, edges[i].cost2);
		}
	}
}

int main(){
	cin >> n >> k >> m;
	for(int i = 1; i <= m - 1; i ++){
		cin >> edges[i].a >> edges[i].b >> edges[i].cost1 >> edges[i].cost2;
	}
	init();
	kruskal1();
	kruskal2();
	cout << ans << endl;
	
	
	return 0;
}