洛谷[USACO07DEC]Building Roads S
题目链接:https://www.luogu.com.cn/problem/P2872
这个题我真的裂开,因为一个j写成了i我硬生生调了一个小时,我一想思路和代码都没问题啊,没想到是j写成了i
这个题可以说是裸题;
看完题你会发现这个题没有给出每个边的权值,那也就是说,边的权值是需要自己去计算的,题目给出求添加的边的总长度的最小值。那么也就是说生成树的权值累计是以边的长度计算的;
并且给出的是每个点的坐标,那么就好办了,边的权值就是两坐标点之间的距离,
这里需要注意的是,我们在进行计算边的权值的时候,是只计算一次的,也就是说,题目给出的是双边存图,但是我们计算权值依旧是要计算一次,因为从一个点到另一个点的距离是定长的,如果按双边计算的话这个权值无疑是扩大了一倍,所以说用求两坐标点之间的距离公式计算即可;
另外还需要注意的是,在输入m行联通边的时候,联通边是本来就存在的,这时候就不需要计算联通边的权值了,我们只需要将其权值置为0,然后记录起点和终点即可;
总体思路:
对每一个点记录坐标
对每两个点都进行距离运算(只用运算一次就够了)
把已经建好的路的权值改成0
Talk is cheap. Show me the code.
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int num=1e6;//开大一点不然有可能RE 4 struct edge 5 { 6 int u; 7 int v; 8 double w;//权值最后输出是浮点数 9 }e[num]; 10 int x[num]; 11 int y[num]; 12 int cnt;//cnt记录边数,单边存即可 13 int n,m; 14 int s[num];//集合 15 double ans; 16 bool cmp(edge a,edge b)//排序 17 { 18 return a.w<b.w; 19 } 20 int find_set(int x)//集合查找+路径压缩 21 { 22 if(x!=s[x]) 23 { 24 s[x]=find_set(s[x]); 25 } 26 return s[x]; 27 } 28 void kruskal()//板子 29 { 30 for(register int i=1;i<=n;i++) 31 s[i]=i; 32 sort(e+1,e+1+cnt,cmp); 33 for(register int i=1;i<=cnt;i++) 34 { 35 int b=find_set(e[i].u); 36 int c=find_set(e[i].v); 37 if(b==c) 38 continue; 39 s[c]=b; 40 ans+=e[i].w; 41 } 42 } 43 int main() 44 { 45 std::ios::sync_with_stdio(false); 46 cin>>n>>m; 47 for(register int i=1;i<=n;i++) 48 { 49 cin>>x[i]>>y[i]; 50 } 51 for(register int i=1;i<=n;i++) 52 { 53 for(register int j=i+1;j<=n;j++) 54 { 55 e[++cnt].u=i; 56 e[cnt].v=j; 57 e[cnt].w=(double)sqrt((double)pow((x[i]-x[j]),2)+(double)pow((y[i]-y[j]),2));//计算权值 58 } 59 } 60 for(register int i=1;i<=m;i++) 61 { 62 int x1,x2; 63 cin>>x1>>x2; 64 e[++cnt].u=x1; 65 e[cnt].v=x2; 66 e[cnt].w=0;//已经存在的边权值清零 67 } 68 kruskal(); 69 printf("%.2f\n",ans); 70 return 0; 71 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/16209513.html