题目描述
城市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;
}