#1098 : 最小生成树二·Kruscal算法

网友投稿 596 2022-11-08

#1098 : 最小生成树二·Kruscal算法

#1098 : 最小生成树二·Kruscal算法

#1098 : 最小生成树二·Kruscal算法

10000ms

1000ms

256MB

描述

随着小Hi拥有城市数目的增加,在之间所使用的Prim算法已经无法继续使用了——但是幸运的是,经过计算机的分析,小Hi已经筛选出了一些比较适合建造道路的路线,这个数量并没有特别的大。

所以问题变成了——小Hi现在手上拥有N座城市,且已知其中一些城市间建造道路的费用,小Hi希望知道,最少花费多少就可以使得任意两座城市都可以通过所建造的道路互相到达(假设有A、B、C三座城市,只需要在AB之间和BC之间建造道路,那么AC之间也是可以通过这两条道路连通的)。

提示:积累的好处在于可以可以随时从自己的知识库中提取想要的!

小Hi的温馨提示:边的费用在某些时候可以被理解成为边的长度、边的权值等等!所以在后文中各种可能会用上述各种称呼来描述费用一事。

小Ho听到了这个问题,发表了感慨:“这不就是之前最短路问题的时候针对点集变大,但是边集很小的稀疏图么?和​​SPFA算法​​当时遇到的问题很像诶!”

小Hi严肃道:“是的!在现实生活中,大部分的图其实都是稀疏图,哪怕不是,也可以像我这种通过筛选的方式转化为稀疏图!所以稀疏图上的问题是非常重要的!”

“是的!”小Ho连连称是,继续道:“那难道这题也像SPFA那样子来做么?但是最小生成树似乎是不可以用宽度优先搜索来解决的啊?”

“倒也没有那么复杂。”小Hi道:“还记的我们在​​Prim算法​​中得出的结论——对于城市i(i≠1),如果i与城市1的距离不超过其他任何城市j(j≠1)与城市1的距离,那么(1, i)这一条边一定存在于某一棵最小生成树中么?”

“自然记得。”

“我们来把这个结论稍微改一下:图中最短的边一定属于某棵最小生成树。”小Hi说道:“证明是简单的——因为城市1的标号是随意的,也就是无论给哪个城市标1都会有之前的结论,那么对于任意节点来说它连接的所有边中最短的边一定存在于某一棵最小生成树中,而整个图中最短的一条边一定是这样的一条边。”

小Ho道:“是的,那么也就是说我只需要不断的找到当前图中最短的一条边(一开始就将所有的边排序然后从小到大)——这样的一条边一定属于某棵最小生成树!然后我只需要将连接的2个节点合并成为一个新的节点,那么这个问题就变成了一个规模-1的问题了!只需要不断重复这样的操作,就能够使得问题最后变成1的规模,这个时候只需要之前找到的所有一定存在于最小生成树中的边的费用加起来就是答案了就可以了!”

小Hi点了点头,说道:“那么还剩一个问题,在Prim问题中,由于合并都是和1号城市合并,所以只需要简单的记录一个节点是否已经合并进了1号城市就可以了,但是在这里却会复杂很多,你有什么想法么?”

“你这就太小看我的记忆力了!”小Ho抱怨道:“在当年遇到黑叔叔的时候,我们不是学会了一种​​并查集​​的方法么?在这里只需要用并查集维护哪些节点被合并到了一起,不就行了?”

“嗯~ o(* ̄▽ ̄*)o,算你聪明,赶紧去实现程序吧!”

输入

每个测试点(输入文件)有且仅有一组测试数据

在一组测试数据中:

第1行为2个整数N、M,表示小Hi拥有的城市数量和小Hi筛选出路线的条数。

接下来的M行,每行描述一条路线,其中第i行为3个整数N1_i, N2_i, V_i,分别表示这条路线的两个端点和在这条路线上建造道路的费用。

对于100%的数据,满足N<=10^5, M<=10^6,于任意i满足1<=N1_i, N2_i<=N, N1_i≠N2_i, 1<=V_i<=10^3.

对于100%的数据,满足一定存在一种方案,使得任意两座城市都可以互相到达。

输出

对于每组测试数据,输出1个整数Ans,表示为了使任意两座城市都可以通过所建造的道路互相到达至少需要的建造费用。

样例输入

5 29 1 2 674 2 3 249 3 4 672 4 5 933 1 2 788 3 4 147 2 4 504 3 4 38 1 3 65 3 5 6 1 5 865 1 3 590 1 4 682 2 4 227 2 4 636 1 4 312 1 3 143 2 5 158 2 3 516 3 5 102 1 5 605 1 4 99 4 5 224 2 4 198 3 5 894 1 5 845 3 4 7 2 4 14 1 4 185

样例输出

92

AC代码:

#include #include #include #include #include using namespace std;struct Node{ int u; int v; int cost;}e[1000006];int fa[100005];bool com(Node p,Node q) //升序排序 { return p.cost < q.cost;}int find(int x) //并查集 { if(x == fa[x]) { return x; } return fa[x] = find(fa[x]);}int main(){ int n,m; cin>>n>>m; for(int i = 0;i < m;i++) { scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].cost); } sort(e,e + m,com); //排序 for(int i = 1;i <= n;i++) { fa[i] = i; } int k = 0; int res = 0; int x,y; int cnt = 0; for(int i = 1;i < n;i++) //找n-1条边 { for(int j = k;j < m;j++) //找最小边 { x = find(e[j].u); y = find(e[j].v); if(x == y) //属于同一个集合 { continue; } fa[x] = y; // 加入同一个集合 res += e[j].cost; k = j + 1; break; //找到了一条 } } printf("%d\n",res); return 0;}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:2013 带分数
下一篇:#1040 : 矩形判断
相关文章

 发表评论

暂时没有评论,来抢沙发吧~