hoj 1863 最小生成树

来源:互联网 发布:原野发胶淘宝假货 编辑:程序博客网 时间:2024/05/22 15:45

哎呀最小生成树呀··哎呀MST啊··纠结了我快一星期=.=  。kruskal 和 prim想着都还行,但代码实现起来,就是各种错啊。。。

下面是kruskal的方法,比较有代表性意义,加上注释~~

 

 

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#include <algorithm>using namespace std;int n,m,p,par[150];struct vil{int u,v;//某边的左右端点 int w;  //某边的权值 }edge[150];void input(){int n_road;int from, to, len;         n_road = n;p = 0;while( n_road-- ){scanf("%d %d %d", &from, &to, &len);edge[p].u = from;   //左结点 edge[p].v = to;     //右结点 edge[p].w = len;    //权值 p++;}}int cmp(const void *a,const void *b){struct vil *c = (vil *)a;struct vil *d = (vil *)b;  return c->w - d->w; // Kruskal的排序是按照权值从小到大的}int findset(int x){int temp;temp = x;x = par[temp];         //优化操作,避免每次都遍历,直接把已经操作过的结点接到树根上 while( x != par[x])   //当x的父节点不是自己,那么就把父结点给x,再往前找,直到找到树根,说明是一个集合 {x = par[x];}return x;}void kruskal(){int i,c; // 记录边数c,满足题中输出?的情况 int a, b;int sum_len;sum_len = c = 0;qsort( edge,p,sizeof(struct vil),cmp );  //这个容易错 for ( i = 0; i <= m; i++ ){par[i] = i;                          //初始化父节点,让他们都指向自身,开始时是离散关系 }for ( i = 0; i < n; i++ ){a = findset( edge[i].u ); b = findset( edge[i].v );if ( a != b )                        //找到最小边后,两边的结点,如果不在一个集合里,就加上len,并合并 {sum_len += edge[i].w;par[b] = a;           //将b并入a集合c++;  // 增加边数}}if (c==m-1) // m-1条边的时候为满足要求{printf("%d\n", sum_len);}else{printf("?\n");}}int main(){while( scanf("%d %d",&n, &m) != EOF ){int t;if ( n == 0 ){break;}else{input();              //输入输出比较有意思,注意下~~ kruskal();}}return 0;}