解题报告:有n个点,然后有m条可以添加的边,然后有一个k输入,表示一开始已经有k个集合的点,每个集合的点表示现在已经是连通的了。

还是用并查集加克鲁斯卡尔。只是在输入已经连通的集合的时候,通过并查集将该集合的点标记到一起,然后剩下的就可以当成是普通的最小生成树来做了题目代码如下:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cstdlib>
 6 using namespace std;
 7 
 8 struct node
 9 {
10     int front ,rear,cost;
11 }rode[25005];
12 int pre[505];
13 int find(int n)
14 {
15     return pre[n] == n? n:pre[n] = find(pre[n]);
16 }
17 int cmp(const void *a,const void *b)
18 {
19     return (*(node*)a).cost <= (*(node*)b).cost? -1:1;
20 }
21 int judge(int n)
22 {
23     for(int i = 2;i <= n;++i)
24     if(find(1) != find(i))
25     return 0;
26     return 1;
27 }
28 
29 int main()
30 {
31     int T;
32     int ci,s,d;
33     scanf("%d",&T);
34     while(T--)
35     {
36         int n,m,k;
37         scanf("%d%d%d",&n,&m,&k);
38         for(int i = 1;i <= m;++i)
39         scanf("%d%d%d",&rode[i].front,&rode[i].rear,&rode[i].cost);
40         qsort(rode+1,m,sizeof(node),cmp);
41         for(int i = 1;i <= n;++i)
42         pre[i] = i;
43         while(k--)
44         {
45             scanf("%d%d",&ci,&s);
46             ci--;
47             while(ci--)
48             {
49                 scanf("%d",&d);
50                 pre[find(s)] = find(d);
51             }
52         }
53         int ans = 0;
54         for(int i = 1;i <= m;++i)
55         {
56             int temp1 = find(rode[i].front);
57             int temp2 = find(rode[i].rear);
58             if(temp1 != temp2)
59             {
60                 ans += rode[i].cost;
61                 pre[temp1] = temp2;
62             }
63         }
64         printf(judge(n)? "%d\n":"-1\n",ans);
65     }
66     return 0;
67 }
View Code

相关文章: