题目:点击打开链接。
#include<algorithm>
#include<stdio.h>
#include<string.h>
#define MAX 60
#define INF 0x3f3f3f3f
using namespace std;
struct edge{
int u,v,dis;
}e[MAX*MAX/2];//边
int n,fa[60],g[60][60];
void init()//并查集初始化
{
for(int i=0;i<=n;++i)
fa[i]=i;
}
int findd(int x)//找到根父节点
{
if(fa[x]!=x)
fa[x]=findd(fa[x]);
return fa[x];
}
void unionn(int tu,int tv)//连接两个节点
{
int fau=findd(tu);
int fav=findd(tv);
fa[fav]=fau;
}
bool comp(const edge& e1,const edge& e2)//运算符重载
{
return e1.dis<e2.dis;
}
int kruskal(int en)
{
sort(e,e+en,comp);//把边从小到大排序
int res=0;//计路径总长
for(int i=0;i<en;++i)
{
edge nowe=e[i];
if(findd(nowe.u)!=findd(nowe.v))//如果当前边所连接的两个点没有关系,使他们发生关系
{
unionn(nowe.u,nowe.v);
res+=nowe.dis;
}
}
return res;
}
int main()
{
int en,q,a,b,c,m;
while(scanf("%d",&n)&&n)
{
en=0;
scanf("%d",&m);
memset(g,INF,sizeof(g));
while(m--)
{
scanf("%d%d%d",&a,&b,&c);
if(g[min(a,b)][max(a,b)]>c)
g[min(a,b)][max(a,b)]=c;
}//由于两点间有多种可能,所以先写进二维数组找到两点间(直接)最短的边
for(int i=1;i<n;++i)
{
for(int j=i+1;j<=n;++j)
{
if(g[i][j]!=INF)
{
e[en].u=i;
e[en].v=j;
e[en].dis=g[i][j];
++en;
}
}//把数组中的边写进邻接表
}
init();
printf("%d\n",kruskal(en));
}
return 0;
}
kruskal算法用到了并查集这种高效的查找方式,并查集发生的过程是生成数的过程,由小树变成大树的过程,当判断两个元素是否有关系时实际在判断两个元素是否属于同一棵树的过程。sort函数用来排结构体很方便,算法的核心用贪心的思想要找最短总路径,每一步都选择当期最短的路,直到连接所有节点。