我现在做的是第四专题编号为1007的试题,具体内容如下所示:
Problem G
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 62 Accepted Submission(s) : 6
1 6 4 3 1 4 2 2 6 1 2 3 5 3 4 33 2 1 2 2 1 3 3 4 5 6
1
简单题意:
给定n个点,m条边和t个已经联通的集合,求最小生成树。
解题思路:
:kruskal就是以边为中心,每次贪心选择最短边以构建一棵最小生成树,并查集的作用是一开始初始化成n棵树,对应n个节点,每次读入一条边时判断该边的起点和终点是否在同一棵树中,若是则不能读取该边,否则会构成环,若不是同一棵树则将这两棵树合并,记录树总数的变量减一,最后若该变量等于1代表最小生成树已经找到了,若遍历所有边后该变量依旧不等于1则没有最小生成树。
编写代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define maxn 502
#define maxm 25002
int id, pre[maxn];
int count, ans;
struct Node{
int from, to, val;
} edge[maxm];
void addEdge(int a, int b, int c)
{
edge[id].from = a;
edge[id].to = b;
edge[id++].val = c;
}
int unionFind(int k)
{
int a = k;
while(pre[k] != -1) k = pre[k];
int b;
while(a != k){
b = pre[a];
pre[a] = k;
a = b;
}
return k;
}
int cmp(const void* a, const void* b){
return ((Node *)a)->val - ((Node *)b)->val;
}
bool kruskal()
{
qsort(edge, id, sizeof(Node), cmp);
int x, y, i;
for(i = 0; i < id; ++i){
x = unionFind(edge[i].from);
y = unionFind(edge[i].to);
if(x != y){
ans += edge[i].val;
--count; pre[y] = x;
if(1 == count) return true;
}
}
return 1 == count;
}
int main()
{
int cas, n, m, k, t, a, b, c, i;
scanf("%d", &cas);
while(cas--){
memset(pre, -1, sizeof(pre));
scanf("%d%d%d", &n, &m, &k);
for(i = id = 0; i < m; ++i){
scanf("%d%d%d", &a, &b, &c);
addEdge(a, b, c);
}
count = n; ans = 0;
for(i = 0; i < k; ++i){
scanf("%d%d", &t, &a);
a = unionFind(a);
while(--t){
scanf("%d", &b);
b = unionFind(b);
if(a != b){
pre[b] = a;
--count;
}
}
}
if(!kruskal()) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}