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