补一个:我之前学习并查集时看过一篇博客,说的非常透彻,因为kruskal算法也用到了并查集,所以再提一下
链接:博客
一、介绍下kruskal算法
1.记 Graph 中有v个顶点,e个边
2.新建图 Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边
3.将原图 Graphnew 中所有e个边按权值从小到大排序
4.循环:从权值最小的边开始遍历每条边 直至图 Graphnew 中所有的节点都在同一个连通分量中
如果这条边连接的两个节点于图 Graphnew 中不在同一个连通分量中
添加这条边到图 Graphnew 中
二、图片描述
之前看到一个博客总结了一些图论的题:图论题目集合
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
int s,e,w;
} a[25000+5];
int n,m,k;
int fa[505];
bool cmp(node a,node b)
{
return a.w<b.w;
}
int Find(int x)
{
if(fa[x]==x)
return x;
return fa[x]=Find(fa[x]);
}
int Kruskal()
{
sort(a+1,a+m+1,cmp);
int ans=0;
for(int i=1; i<=m; i++)
{
int x=Find(a[i].s);
int y=Find(a[i].e);
if(x!=y)
{
ans+=a[i].w;
fa[x]=y;
}
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>m>>k;
for(int i=1; i<=m; i++)
{
scanf("%d%d%d",&a[i].s,&a[i].e,&a[i].w);
}
for(int i=1; i<=n; i++)
fa[i]=i;
for(int i=1; i<=k; i++)
{
int t,x,y;
scanf("%d%d",&t,&x);
for(int j=2; j<=t; j++)
{
scanf("%d",&y);
int fx=Find(x);
int fy=Find(y);
if(fx!=fy)
fa[fx]=fy;
}
}
int ans=Kruskal();
int sum=0;
for(int i=1; i<=n; i++)
{
if(fa[i]==i)
sum++;
}
if(sum>1)
cout<<"-1"<<endl;
else
cout<<ans<<endl;
}
return 0;
}