试题编号: | 201703-4 |
试题名称: | 地铁修建 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 A市有n个交通枢纽,其中1号和n号非常重要,为了加强运输能力,A市决定在1号到n号枢纽间修建一条地铁。 输入格式 输入的第一行包含两个整数n, m,用一个空格分隔,分别表示交通枢纽的数量和候选隧道的数量。 输出格式 输出一个整数,修建整条地铁线路最少需要的天数。 样例输入 6 6 样例输出 6 样例说明 可以修建的线路有两种。 评测用例规模与约定 对于20%的评测用例,1 ≤ n ≤ 10,1 ≤ m ≤ 20; |
思路:根据克鲁斯卡尔算法,运用并查集很容易求得一条从1到n的路径(不一定是最短的)但要求这条路径中最长的边尽量短,
这与迪斯科最短路径还有点稍微不同
#include<iostream>
#include<algorithm>
#define maxn 100005
#define maxm 200005
using namespace std;
struct edge{
int from;
int to;
int cost;
}edge[maxm];
int pre[maxn];//并查集
int find(int x){
//非递归
int k,j,r;
//r根节点,
r=x;
while(r!=pre[r])
r=pre[r];
//压缩路径
k=x;
while(k!=r){
j=pre[k];
pre[k]=r;
k=j;
}
return r;
//递归找根
/* if(pre[x] == x) {
return x;
} else {
return pre[x] = find(pre[x]);
}*/
}
bool cmp(struct edge a,struct edge b){
return a.cost<b.cost;
}
void unite(int x,int y){
int f1=find(x);
int f2=find(y);
if(f1!=f2){
pre[f1]=f2;
}
}
int main(){
int n,m;
int num=0;
int cost_max;
cin>>n>>m;
for(int i=0;i<m;i++)
cin>>edge[i].from>>edge[i].to>>edge[i].cost;
//初始化n个连通分量
for(int i=0;i<n;i++)
pre[i]=i;
sort(edge,edge+m,cmp);//输入数组地址
while(find(1)!=find(n))
{
unite(edge[num].from,edge[num].to);
cost_max=edge[num].cost;
num++;
}
cout<<cost_max;
return 0;
}
代码需要注意两点
1、在find函数里,运用两种方式实现,非递归算法和递归算法,其中非递归算法中要压缩路径,不然会导致运行超时,只得90分,压缩路径之后,运行593ms,递归运行656ms
2、并没有用到rank【】数组来计算树的高度,以此来简便代码