这题要注意的是,对已经存在的连通的边,直接合并,不要建边,这样可以省时间
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
struct node{
int u,v;
int w;
}e[50000];
int n,m,father[50000];
int cmp(node a,node b){
return a.w<b.w;
}
int findroot(int p){
if(father[p]!=p)
father[p]=findroot(father[p]);
return father[p];
}
void unionset(int p,int q){
father[q]=p;
}
int kruskal(int k){
int res=0;
int j=0;
while(k<n&&j<m){
int m1=e[j].u,m2=e[j].v;
int sn1=findroot(m1),sn2=findroot(m2);
if(sn1!=sn2){
res+=e[j].w;k++;
unionset(sn1,sn2);
}
j++;
}
if(k!=n)res=-1;
return res;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int k;
scanf("%d%d%d",&n,&m,&k);
int i,j;
for(i=1;i<=n;i++)father[i]=i;
for(i=0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[i].u=u;e[i].v=v;
e[i].w=w;
}
int sum=1; //代表已经建边的边数,用于判断是否能够联通
for(i=0;i<k;i++){
int num;
scanf("%d",&num);
int x;
scanf("%d",&x);
x=findroot(x);
for(j=1;j<num;j++){//如果已经连接,不要再次建边,会T,直接合并点就可以
int y;
scanf("%d",&y);
y=findroot(y);
if(x!=y){
unionset(x,y);
sum++;
}
}
}
sort(e,e+m,cmp);
int ans=kruskal(sum);
printf("%d\n",ans);
}
return 0;
}