什么是最小生成树
在图{V,E}中,使用E中的边将V中所有的点联通,使其成为树,要求树中边权之和最小,这就是最小生成树。
prim算法
1.复杂度:O(n2)
2.适用范围:与dijkstra算法类似,不能处理负权边
3.思想:与dijkstra算法类似,松弛。找到距离源点(这里的源点任意)最近的点,如此循环。
4.代码实现:
int mp[maxn][maxn],in[maxn],d[maxn];
//d[maxn]数组记录从树出发到i点的距离最小值,in[maxn]记录i点是否在集合中
int V;
int prim()
{
for(int i = 1; i<=V; i++)
{
in[i] = 0;
d[i] = INF;
}
d[1] = 0;
int res = 0,sum = 0;
while(true)
{
int pos = -1;
for(int i = 1; i<=V; i++)
{
if(!in[i] && (pos == -1 || d[i]<d[pos]))
pos = i;
}
if(pos == -1 || d[pos] == INF) break;
in[[pos] = 1;
res += d[pos];
sum++;
for(int i = 1; i<=V; i++)
{
d[i] = min(d[i],d[pos]+mp[pos][i]);
}
}
if(sum == V) return res;
else return -1;
}
并查集计算最小生成树
1.复杂度:O(n2)
2.适用范围:朴素并查集可以解决普通最小生成树,可以通过加入其他算法解决负权问题
3.思想:沿着最短边找根,当然,如果找到多于一个根,则不能生成最小生成树
4.代码实现:
int n,m,fa[maxn],cnt;
struct edge{
int u,v,w;
};
bool cmp(edge e1,edg2 e2)
{
return e1.w<e2.w;
}
void init(int m)
{
cnt = 0;
for(int i = 0; i<=m; i++)
fa[i] = i;
}
int findfa(int i)
{
while(i != fa[i])
i = fa[i];
return i;
}
int merge(int i, int j)
{
i = findfa(i);
j = findfa(j);
if(i != j)
{
fa[i] = j;
return 1;
}
return 0;
}
int main()
{
while(scanf("%d %d",&n,&m) != EOF)
{
edge mp[maxn];
init(m);
for(int i = 0; i<n; i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
mp[i].u = u;
mp[i].v = v;
mp[i].w = w;
}
sort(mp,mp+n,cmp);
int res = 0;
for(int i = 0; i<n; i++)
{
if(merge(mp[i].u,mp[i].v))
res += mp[i].w;
}
for(int i = 0; i<=m; i++)
{
if(fa[i] == i) cnt++;
}
if(cnt == 1) printf("%d\n",res);
else printf("No\n");
}
}