题目:http://acm.hdu.edu.cn/showproblem.php?pid=1863
最小生成树kruskal算法:http://www.zhuoda.org/irini/78592.html
一开始看到题目的时候就知道是求最小生成树的题目,而且可以用并查集了构建树,但是不知道怎么将并查集和求最小生成树的算法结合起来,后来看到了
最小生成树Kruskal算法是用贪心求最小生成树的,每次都都取权值最小的边去构建树,如果两点的祖先结点相同,及直接连通或者间接连通的时候则不再建边
否则创建边使连点直接或间接连通。
实现算法如下:
#include<stdio.h> #include<algorithm> #include<string.h> #define MAXN 105 int C[MAXN],W[MAXN][MAXN]; struct node { int x,y; int w; }arr[105]; int cmp(const void *a,const void *b) { node *pa = (node*)a; node *pb = (node*)b; return pa->w > pb ? 1 : pa->w < pb->w ? -1 : 0; } void init(int n)//初始化结点的祖先结点为它本身 { int i; for(i = 1; i<= n; i++) C[i] = i; } int find(int x)//找到树的根节点 { int r ; r = C[x]; while(r != C[r]) r = C[r]; return r; } int main() { int N,M,i,n,Min; int a,b; while(scanf("%d%d",&N,&M) != EOF,N) { //输入所有的结点及边的权值 for(i = 0; i < N; i++) scanf("%d%d%d",&arr[i].x,&arr[i].y,&arr[i].w); //按权值从小到大进行排序 qsort(arr,N,sizeof(node),cmp); // for(i = 0;i <N; i++) // printf("%d %d %d\n",arr[i].x,arr[i].y,arr[i].w); init(M); Min = 0; for(i = 0; i < N; i++)//采用并查集实现最小生成树kruskal { //求结点arr[i].x的祖先结点和arr[i].y的祖先结点 a = find(arr[i].x); b = find(arr[i].y); if( a != b) {//当不连通的时候将两棵树的祖先结点连通,权值的最小值加上arr[i].x到arr[i].y的权值 M --; C[a] = b; Min += arr[i].w; } } if(M > 1)//所有结点不能组成一颗树的时候输出?否则输出最小生成树的权值和 printf("?\n"); else printf("%d\n",Min); } return 0; }