Description
Kerry 是德国的一位电缆商人。因联合国脱贫计划的邀请,他准备负责在土鲁齐亚埃萨亚克斯乌托斯邦建立电缆网络,以满足这个国家的用电需求。当然,现在土鲁齐亚埃萨亚克斯乌托斯邦没有任何电缆。已知土鲁齐亚埃萨亚克斯乌托斯邦一共有n个城镇,已经编号为1到n。其中任意两个城镇可能有一条路,也可能没有。如果两个城镇之间有一条路pi,那么这条路有一个长度si,则Kerry可以在这两个城市之间建立一条电缆线,电缆线的长度也就是这条路的长度si。
现在Kerry准备了s长的电缆线,电缆线可以任意拆断,拆断不损失任何电缆线。他需要将土鲁齐亚埃萨亚克斯乌托斯邦所有城镇都能够连入这个电缆网络。那么,Kenny能不能使用这s长度的电缆线完成这项工作;如果能够完成,那么Kerry最少耗用多少长度的电缆线呢?Input
第一行一个正实数S;
第二行一个正整数n;
接下来一共有m行(m是个未知数),第i行有两个整数xi,yi和一个实数si,表示编号为xi个村庄和编号为yi个村庄之间有一条路,路的长度为si。
输入保证xi不等于yi,两个城镇之间不会有两条路。Output
若能够完成(建立这样的电缆网络),则输出(其中代表最少的电缆线长度,保留两位小数):
Needmiles of cable
否则输出:
Impossible
Sample Input
100.0
4
1 2 2.0
1 3 4.2
1 4 6.7
3 4 4.0
2 4 10.0
Sample Output
Need 10.20 miles of cable
HINT
1<=n,m<=100000
分析
最小生成树—kruskal算法+并查集
将边权从小到大排序,依次将权值最小的边加入最小生成树中(也叫加边法),用并查集判断是否构成环。当边数=顶点数-1时,所有顶点(城市)已经在最小生成树,也就是电缆网络中。最后判断所需最小长度是否大于s,如果在范围内,按题目要求输出;如果不在,输出Impossible
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
double mincost,cost,s1;
int f[100010],s,t,j,n,ans;
int find(int x){
if(f[x]==x)return x;
return f[x]=find(f[x]);//路径压缩
}
struct Edge{
int a,b;
double w;
}edge[100010];
bool cmp(Edge a,Edge b){
return a.w<b.w;
}
int main(){
scanf("%lf%d",&s1,&n);
while(scanf("%d%d%lf",&s,&t,&cost)!=EOF){
j++;
edge[j]={s,t,cost};
}
sort(edge+1,edge+1+j,cmp);//边权从大到小排序
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<=j;i++){
int fx=find(edge[i].a);
int fy=find(edge[i].b);
if(fx!=fy){//用并查集判断顶点是否已经在最小生成树中,也就是判断是否构成环
ans++;
mincost+=edge[i].w;
f[fx]=fy;
}
if(ans==n-1) break;//所有顶点已经在最小生成树中
}
if(mincost<=s1&&ans==n-1){//判断
printf("Need %.2lf miles of cable",mincost);
}else{
cout<<"Impossible"<<endl;
}
return 0;
}