并查集实现kruskal算法

kruskal算法:求最小生成树,给定n个节点,m条边和边的权值,创建一个总权值最小的树

这里用到了并查集的思想:如果要加入的边两个顶点在同一个集合里(代码里即为find(int x)相同),就说明会形成环,这是不行的,否则抓出最小的那条边,放入集合之中,并且标记这条边,下次遍历的时候跳过

到集合总边数为n-1时,不必再寻找,跳出循环。

#include<iostream>
#include<algorithm>
#define maxn 100
using namespace std;
int fa[maxn];
int edge[maxn][maxn];
int vis[maxn];
typedef struct node
{
 int to;
 int end;
 int x;//权值
}node;
node nod[maxn];
void init(int n)
{
 for(int i=1;i<=n;i++)
 {
  fa[i]=i;
 }
}
int find(int x)
{
 if(x==fa[x])
  return x;
 else
  return fa[x]=find(fa[x]);
}
void uni(int x,int y)
{
 int xnn=find(x);
 int ynn=find(y);
 if(xnn!=ynn)
  fa[xnn]=ynn;
}
int main()
{
 int n;//点数
 int m;//边数
 cin>>n>>m;
 for(int i=1;i<=m;i++)
 {
  cin>>nod[i].to;
  cin>>nod[i].end;
  cin>>nod[i].x;
 }
 init(n);
 int count=0;
 int sum=0;
 while(1)
 {
  int minn=1e9;
  int pos=-1;
  if(count==n-1)//边数=点数-1,说明已经建立完了一个图;
  {
   break;
  }
  //找最小的边
  for(int i=1;i<=m;i++)
  {
   if(vis[i]==0/*这个边没找过*/&&minn>nod[i].x/*找最小边*/&&find(nod[i].to)!=find(nod[i].end)/*两个点不在同一个集合里*/)
   {
    minn=nod[i].x;
    pos=i;
   }
  }
  vis[pos]=1;//说明这个边已经加入了
  sum+=nod[pos].x;
  uni(nod[pos].to,nod[pos].end);
  count++;
 }
 cout<<sum<<endl;
}

改进:可以先将所有边按权值在开头排序好,就不用一遍一遍找了。代码懒得改了

发布了16 篇原创文章 · 获赞 1 · 访问量 273

猜你喜欢

转载自blog.csdn.net/weixin_44254608/article/details/104615005