1) 开始时,MST包含n个顶点,0条边;每个点都不连通,每个点为单独的一组;
2) 将边的权值按照从小到大排列,每次选取最小的权值边<u,v>加入到最小生成树中,加入的过程中要注意的地方是:
不能产生环,那么如何判断呢?
可以这样:在添加权值边<u,v>, 在添加之前,我们要判断u、v是否已经连通,若是,则不能添加这条边到MST中,反之,可以添加;
那么,如何判断u、v两个顶点是否 已经连通呢?
可以通过看u、v是否在相同的组中,相同组的顶点之间是连通的,不同组的顶点是不连通的。那么如何来描述组的这个概念呢?
我们将所有的结点以整数表示,即对N个结点使用0—N-1的整数表示,开始的时候每个结点都是孤立的,即他们分别属于不同的组,可以用数组来表示这一 层关系,数组 的下标表示结点,相应的数组值表示该结点的组号;
so,数组可以初始化为:
for(int i=0;i<n;++i)
id[i] = i;
这样,每当输入一个权值边<u、v>的时候,首先通过id数组判断u v是否在同一组中,若在,则舍弃<u、v>;反之,则将<u v>加入MST,并将他们的合并成一组,即将其中一个结点的组号换成另一个结点的组号;
这样,对于每一条边,我们的算法可能要涉及到对数组的查找和修改,因此,我们可以考虑将结点和组的关系以树的形式表现出来。所以在数组中,我们可 以采用将结点以parent-link的方式组织起来,eg: id[p] 的值就是p结点的父结点的序号,如果p是树根的话,id[p]的值就是p, 因此,经过若干次查找,一个结点总是能够找到它的根结点,然后就可以利用根结点的序号来表示组号,所以在处理一个pair的时候,将首先找到pair<u v>中每一个结点的组号(它们所在树的根结点的序号),如果组号不相同 ,将pair计入MST,并且将u( or v)所在组的根结点的父节点设置为v (or u)所在组的根节点;相当于将一颗独立的树变成另一颗独立的树的子树。
const int MAX=100;
int parent[100];//parent[i]表示结点i的父节点(或者是爷爷结点)
int sz[100] = { 1 };//以结点i为根结点,其子节点有多少个(包括结点i)(树的大小)
struct node
{
int begin;
int end;
int w;
}edge[MAX];
bool cmp(node a, node b)
{
return a.w < b.w;
}
int find(int p)
{
while (p != parent[p])
{
parent[p] = parent[parent[p]];
p = p[parent];
}
return p;
}
void unionMerge(int begin, int end)
{
int i = find(begin);
int j = find(end);
if (i == j)
return;
if (sz[i] < sz[j])
{
parent[i] = j;
sz[j] += sz[i];
}
else
{
parent[j] = i;
sz[i] += sz[j];
}
cout << "最小生成树中包含边:<"
<< begin << "," << end << ">" << endl;
}
void kruscal(int m)
{
for (int i = 0; i < m; ++i)
{
int u = edge[i].begin;
int v = edge[i].end;
unionMerge(u, v);
}
}
void main()
{
int n, m;
cin >> n >> m;
for (int i = 0; i < MAX; ++i)
parent[i] = i;
for (int i = 0; i < m; ++i)
{
cin >> edge[i].begin >> edge[i].end >> edge[i].w;
}
sort(edge, edge + m, cmp);
kruscal(m);
}