为了响应国家“退耕还林”的号召,丁丁妹正在将她的大头菜田改形成树林。ios
然而这和这道题并无什么关系。算法
重要的是,丁丁妹思考了以下一个问题:数组
给定一个有n 个点m 条边的无向图,每条边有一个边权c 。ide
如何选择n−1 条边来让这个无向图连通,而且使得这n−1条边的边权之和最小呢?函数
显然这个问题对于丁丁妹来讲太困难了,因而她又花重金聘请了你,但愿你来解决这个问题。 优化
单组数据,第一行为两个正整数n,m 。spa
接下来m 行,每行有三个正整数x,y,c ,表示x 号点和y号点之间存在一条边权为c 的无向边。code
数据保证:blog
1. 对于80% 的数据, 1 ≤ n,m ≤ 1000排序
2. 对于100% 的数据,1≤n,m≤1000000
3. 对于100% 的数据, 1 ≤ c ≤ 100
一个整数 c ,表明边权之和的最小值;若没法选择n−1条边让图连通,输出− 1 。
3 3
1 2 1
1 3 2
2 3 3
3
这个题一看数据量 1e6 这么大,指定不能用二维数组,因此最短路或者dp直接求实在是行不通,
问的是联通图, 最短连通路径,又须要压缩空间来优化, 很容易就想到并查集
另外, 注意这里说的连通路径不是那种"一笔画的"欧拉路, 而是 ------- 连通的可交叉的路径-------相似一棵树
实际上---------最小生成树------------就是咱们要求的连通路径
问题在于怎么使用并查集来表示一条完整的,"从1-n都能连通的路径",另外每条路径都该怎么算出来
并查集来表示存在的连通关系, 咱们知道 find()函数就是为了 将全部连通的节点归到同一个"根"上面,
这样能够造成一个"同根树",若是发现全部的节点都只有一个根, 说明这个图是联通的,
最小生成树的求解-----Kruskal算法/Prim算法-----实际上就是贪心!!!
这里用Kruskal , 咱们把全部的边排序,每次操做,
最后只检查新边是否和成环,最后检查是否全部的点都连通,检查边的数目是否为n-1便可
注意合并是怎样的,好比
6 和 4
1 3 5 2 7
存在5,2 之间有一条边, 显然不是5-2合并,由于这样就会有两个根了, 检测连通靠的是根是否相同,
因此, 另外一棵树的根, 也就是6 ,接到另外一棵树,
至于怎么接, 这里看须要, 若是保持结构的话, 就要以5为根旋转成,
5 相似于平衡树, 6的爸爸变成5, 而后 5 的爸爸变成2,这样就保持了原来的结构性质
6
1 3
若是须要完全压缩,尽可能优化查找时间,那就让, 6, 1, 3, 5 的爸爸变成 4
假如不要求时间和效率, 咱们只要求联通路径长, 简单合并就能够了
----好比, 6---右边的爸爸-------变成--------左边的爸爸-------2也能够获得确结果,以下代码, 可是会TE
1 int l=find(x[i].l); 2 int r=find(x[i].r); 3 f(r!=l) { 4 k++; 5 ans+=x[i].d; 6 f[r]=x[i].l; 7 }
改为了把6的爸爸变成4, 仍是TE,6---右边的爸爸-------变成--------左边的爸爸-------2
1 if(r!=l) { 2 k++; 3 ans+=x[i].d; 4 f[r]=l; 5 }
缘由在于没有固定好一个策略合并, "右边的合并到左边的"并非一个有序的策略,
由于节点是有序号的, 可是, 输入的时候并无规定大的节点必定在右边
也不能保证, 好比大的节点合并到小的那里去,
因此加个判断条件,改为这样就过了
1 if(r!=l) { 2 k++; 3 ans+=x[i].d; 4 if(r>l)f[r]=l; 5 else f[l]=r; 6 }
完整代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int M=1000000+10; 8 int n,m; 9 struct D { 10 int l,r; 11 int d; 12 D() { 13 l=0,r=0,d=0; 14 } 15 } x[M]; 16 int f[M]; 17 void init() { 18 for(int i=1; i<=n; i++) { 19 f[i]=i; 20 } 21 } 22 int find(int t) { 23 return f[t]==t?t:find(f[t]); 24 } 25 /* 26 int find(int t1) { 27 int t=t1; 28 while(f[t]!=t) { 29 t=f[t]; 30 } 31 return t; 32 } 33 */ 34 bool cmp(D a,D b) { 35 return a.d<b.d; 36 } 37 int main () { 38 memset(x,0,sizeof(x)); 39 scanf("%d%d",&n,&m); 40 init(); 41 ll ans=0; 42 for(int i=1; i<=m; i++) { 43 int l,r; 44 scanf("%d%d%d",&x[i].l,&x[i].r,&x[i].d); 45 } 46 sort(x+1,x+1+m,cmp); 47 int k=0; 48 bool t=0; 49 for(int i=1; i<=m; i++) { 50 int l=find(x[i].l); 51 int r=find(x[i].r); 52 if(r!=l) { 53 k++; 54 ans+=x[i].d; 55 if(r>l)f[r]=l; 56 else f[l]=r; 57 } 58 if(k==n-1) { 59 t=1; 60 break; 61 } 62 } 63 if(t==0)cout<<"-1"; 64 else printf("%lld",ans); 65 cout<<"\n"; 66 return 0; 67 }