题目描述
城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造。
城市C的道路是这样分布的:
城市中有 n 个交叉路口,编号是 1∼n ,有些交叉路口之间有道路相连,两个交叉路口之间最多有一条道路相连接。
这些道路是 双向 的,且把所有的交叉路口直接或间接的连接起来了。
每条道路都有一个分值,分值越小表示这个道路越繁忙,越需要进行改造。
但是市政府的资金有限,市长希望进行改造的道路越少越好,于是他提出下面的要求:
1.改造的那些道路能够把所有的交叉路口直接或间接的连通起来。
2.在满足要求1的情况下,改造的道路尽量少。
3.在满足要求1、2的情况下,改造的那些道路中分值最大值尽量小。
作为市规划局的你,应当作出最佳的决策,选择那些道路应当被修建。
输入格式
第一行有两个整数 n,m 表示城市有 n 个交叉路口, m 条道路。
接下来 m 行是对每条道路的描述,每行包含三个整数 u,v,c 表示交叉路口 u 和 v 之间有道路相连,分值为 c 。
输出格式
两个整数 s,max ,表示你选出了几条道路,分值最大的那条道路的分值是多少。
数据范围
1≤n≤300 ,
1≤m≤8000 ,
1≤c≤10000
样例
输入样例:
4 5
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8
输出样例:
3 6
算法1
(Kruskal)
最小生成树的变形,让我们输出枝干数和树中最大的边权.
可以用Kruskal算法一条一条连过去.
C++ 代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,INF=0x3f3f3f3f;
int dis[N],f[N],n,m,cnt;//cnt表示边数
int find(int x)//并查集常规操作之一
{
return f[x]==x?x:f[x]=find(f[x]);//在找爸爸的同时进行优化(把自己这一块的最大爸爸作为f[x]储存的值)
}
struct Edge//结构体存数据
{
int a,b,w;
bool operator<(const Edge &W)const{
return w<W.w;
}//重载运算符方便之后的sort排序,或者用下面的cmp
}edges[N];
/*
bool cmp(Edge a,Edge b)
{
return a.w<b.w;
}
*/
int Kruskal()//主角登场
{
for(int i=1;i<=n;i++) f[i]=i;//并查集常规操作之二,把自己一开始的爸爸设成自己
sort(edges,edges+m);//按权重从小到大排序
/*
sort(edges,edges+m,cmp);
*/
int res=0;
for(int i=0;i<m;i++)
{
int a=edges[i].a,b=edges[i].b,w=edges[i].w;
int f1=find(a),f2=find(b);
if(f1!=f2)//最大爸爸不同,即这两块地方没有连上
{
f[f1]=f2;//或者f[f2]=f1;
res=w;
cnt++;//手动连边
}
}
if(cnt<n-1) return INF;//连不上的情况下返回INF
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
edges[i]={a,b,w};
}
int ans=Kruskal();
printf("%d %d\n",cnt,ans);
return 0;
}