P2330 [SCOI2005]繁忙的都市

題目描述

城市C是一個非常繁忙的大都市,城市中的道路十分的擁擠,於是市長決定對其中的道路進行改造。城市C的道路是這樣分佈的:城市中有n個交叉路口,有些交叉路口之間有道路相連,兩個交叉路口之間最多有一條道路相連接。這些道路是雙向的,且把所有的交叉路口直接或間接的連接起來了。每條道路都有一個分值,分值越小表示這個道路越繁忙,越需要進行改造。但是市政府的資金有限,市長希望進行改造的道路越少越好,於是他提出下面的要求:

1.改造的那些道路能夠把所有的交叉路口直接或間接的連通起來。 2.在滿足要求1的情況下,改造的道路儘量少。 3.在滿足要求1、2的情況下,改造的那些道路中分值最大的道路分值儘量小。

任務:作爲市規劃局的你,應當作出最佳的決策,選擇那些道路應當被修建。

輸入格式

第一行有兩個整數n,m表示城市有n個交叉路口,m條道路。

接下來m行是對每條道路的描述,u, v, c表示交叉路口u和v之間有道路相連,分值爲c。(1≤n≤300,1≤c≤10000,1≤m≤100000)

輸出格式

兩個整數s, max,表示你選出了幾條道路,分值最大的那條道路的分值是多少。

輸入輸出樣例

輸入 #1

4 5
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8

輸出 #1

3 6
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<unordered_map>
#include<set>
#include<sstream>
using namespace std;
const int MAXN = 305; 

struct Node{
	int u,v,w;
	Node(int u,int v,int w){
		this->u = u;
		this->v = v;
		this->w = w;
	}
};
vector<Node> edge;
int father[MAXN]; //father[i]=u 表示i節點的祖先是u,注意:是祖先不是父親,是最高節點而不是上層節點。 

int findFather(int x){
	int z = x;  //保存x的值 
	int temp;
	while(x != father[x]){  //先while循環找到x的祖先,當退出循環時x的值就是祖先的下標  
		x = father[x];
	}
	/*
	**重新從z出發(此時的z就是最初的x),找到它的祖先, 
	**並且在這個過程中把所經過節點的祖先都改成x。 
	**這個東西學名叫作"路徑壓縮",大家可以搜一搜,瞭解一下。 
	**/
	while(z != father[z]){ //跟上面的while(x != father[x])作用一致 
		temp = z;   //保存z的值 
		z = father[z];  //跟上面的x = father[x];作用一致 
		father[temp] = x; //把他所有的上層節點的祖先都改成x
	}
	return x; //此時x的值不是一開始的形參值了,已經是祖先的下標了 
}

//看看x和y的祖先是不是同一個,如果不是,將y的祖先的父親變成x的祖先 
bool unionFather(int x,int y){
	int flag = false;
	int fx = findFather(x);
	int fy = findFather(y);
	if(fx != fy){  //說明x和y節點不在同一個連通塊內,則x---y這條邊可以加入到生成樹中。 
		father[fy] = fx;
		flag = true; 
	} 
	return flag;
} 

void initFather(int n){
	for(int i=0;i<=n;i++){
		father[i] = i;
	}
}

bool cmp(Node &node1,Node &node2){
	return node1.w < node2.w;
}

int edgeNum; //生成樹中包含的邊數 
int maxCost; //分值最大的那條道路的分值 
bool kruskal(int n){
	int u,v,c,fu,fv;
	edgeNum = 0; //生成樹中包含的邊數 
	maxCost = -1;//總花費 
	initFather(n); 
	sort(edge.begin(),edge.end(),cmp); //將邊按照c進行從小到大排序 
	for(int i=0;i<edge.size();i++){
		u = edge[i].u;
		v = edge[i].v;
		c = edge[i].w;
		if(unionFather(u,v)) {//如果u,v不在一個連通塊內 
			edgeNum++; //把u---v這條邊加入到生成樹中了。
			maxCost = max(maxCost,c);
			if(edgeNum == n-1){  //生成樹已經建立好了 
				return true; 
			}
		}
	}
	return false; //說明不是連通圖 
}

int main(){
	int n,m;
	int u,v,c;
	cin>>n>>m;
	while(m--){
		cin>>u>>v>>c;
		edge.push_back(Node(u,v,c));
	} 
	kruskal(n);
	cout<<edgeNum<<" "<<maxCost<<endl;
	return 0; 
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章