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; 
} 

 

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