最小生成树,回忆复习篇。
以前听过一遍最小生成树,可惜,当时没弄会。过了几天就全忘了。而如今在做LCA的时候,woc我居然不会最小生成树了。
所以来回忆一下最小生成树。
kruskal算法。这个算法的主要工具就是,排序,并查集。这里的排序是一种贪心做法。把边权最小的边排在前面,之后开始一个一个取。每次都取小的边,取到n-1条边(刚好遍历每个点)但是每次取的时候都要保证这条边加在这棵最小生成树里面不会产生环,所以,这里用并查集就是记录每次加边时的点,不让加的这条边的两节点连在一起之后产生环。如果这条边连上没产生环,那么它们的父亲就相连.这样让这个并查集组成的树的节点相连,而不是子节点相连,这个地方可以去翻阅并查集的资料。这里不在多说什么。
其实就是这么简单,并不是很难。这棵树遍历了所有的点,而且保证最短。而这就是一个工具模型。嗯就是这样。
我觉得这个没必要模拟。所以这个记住
1,疯狂调sort
2,瞎基本用并查集连边。
嗯,记住如果要使用得从新建树。
好了。来一道模版压压惊。
codevs1078 最小生成树
题目描述 Description
农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了使花费最少,他想铺设最短的光纤去连接所有的农场。 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。 每两个农场间的距离不会超过100000
输入描述 Input Description
第一行: 农场的个数,N(3<=N<=100)。
第二行..结尾: 接下来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,他们每行限制在80个字符以内,因此,某些行会紧接着另一些行。当然,对角线将会是0,因为线路从第i个农场到它本身的距离在本题中没有意义。
输出描述 Output Description
只有一个输出,是连接到每个农场的光纤的最小长度和。
样例输入 Sample Input
4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0
样例输出 Sample Output
28
这道题,就是找一个最小生成树之后把边都加起来
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
struct node{
int v,next,val;
}edge[10001];
struct node_1{
int x,y,z;
}map_1[10001];
int father[100001],head[100001];
int find_1(int x)
{
return father[x]==x?x:father[x]=find_1(father[x]);//并查集路径优化。
}
int cmp(node_1 a,node_1 b)
{
return a.z<b.z;
}
int main()
{
int n,z,cnt=0;
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;++i)father[i]=i;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
scanf("%d",&z);
if(j<=i)continue;
map_1[++cnt].x=i;
map_1[cnt].y=j;
map_1[cnt].z=z;
}
sort(map_1+1,map_1+1+cnt,cmp);
int ans=0,cnt_1=0;
for(int i=1;i<=cnt;i++)//这里的cnt很有趣。因为前面的n-1条边可能不会是最小生成树。所以都要遍历一边。
{
int la=find_1(map_1[i].x),lb=find_1(map_1[i].y);
if(la!=lb)//祖宗不一样所以连在一起不会成环。
{
father[lb]=la;
ans+=map_1[i].z;
++cnt_1;
}
if(cnt_1==n-1)break;//注意取边的边数。
}
printf("%d\n",ans);
return 0;
}