题目链接:
https://www.51nod.com/Challenge/Problem.html#problemId=1212
题解:
个人认为本题的题眼在于,将该连通图构成一个二维数组,每两个联通的点为该数组的横纵两坐标值。由于该图为无向图那么如:fan[a][b] 和 fan[b][a]两个地方的权值应该是相等的,也就是说a-b和b-a这两边因为无向,所以这两点之间公用一条道路。
首先,我们先了解一下什么是最小生成树?
最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。
通过我们学的数据结构可知求出最小生成树有两种方法:
1.Kruskal算法
此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
2.Prim算法
此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
本题中我用了第二种方法来实现的代码,如下:
#include<iostream> #include<algorithm> #include<string.h> using namespace std; int min;int n,m; int fan[10005][10005]; int vis[10005],low[10005]; int ss(){ int min,pos,sum=0; memset(vis,0,sizeof(vis)); pos=1; vis[1]=1; for(int i=1;i<=n;i++){ if(i!=pos) low[i]=fan[pos][i]; //此时的low[i]中找到了从点1开始到其他能联通边的权值 } for(int i=1;i<n;i++){ //共n-1条边相加 min=9999999; for(int j=1;j<=n;j++){ //按权值从小到大的顺序找边 if(!vis[j]&&low[j]<min){ //如果这个点没有被联通 min=low[j]; pos=j; } } sum+=min; //将权值大小依次相加。 vis[pos]=1;//标记一下表示此点已经和点1联通 for(int j=1;j<=n;j++){ //此时为找到和上一个点已经连通过的点,它和它能联通的点的边的权值 if(!vis[j]&&low[j]>fan[pos][j]){ low[j]=fan[pos][j]; } } } return sum; } int main(){ while(cin>>n>>m){ int a,b,c; memset(fan,999999,sizeof(fan)); for(int i=1;i<=m;i++){ cin>>a>>b>>c; if(fan[a][b]>c) { //防重边 fan[a][b]=c; fan[b][a]=c; } } cout<<ss()<<endl; } return 0; }