Problem Description
某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
Input
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。
当N为0时,输入结束,该用例不被处理。
Output
对每个测试用例,在1行里输出最小的公路总长度。
Sample Input
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
Sample Output
3
5
Huge input, scanf is recommended.
Huge input, scanf is recommended.
解题思路:①Prim算法的核心就是加点法,每次把离目标集合最小权值的一点加入其中。其算法跟Dijkstra大同小异,不同的是mincost数组记录的是当前点到目标集合的最小权值,下次就取最小权值的端点加入就可以了。其算法时间复杂度是O(n
2),适合稠密图。
②Kruskal算法的核心就是加边法,
AC代码之Prim算法:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int INF = 0x3f3f3f3f; 4 const int maxn = 105; 5 int n,a,b,c,mincost[maxn],cost[maxn][maxn]; 6 bool vis[maxn]; 7 int Prim(){//加点法 8 for(int i=1;i<=n;++i)//这里选取节点1作为起点,mincost为各节点到最小生成树节点集合的最小权值 9 mincost[i]=cost[1][i]; 10 mincost[1]=0;vis[1]=true;//标记已访问 11 int res=0;//计算最小生成树的权值 12 for(int i=1;i<n;++i){ 13 int k=-1;//标记为-1 14 for(int j=1;j<=n;++j)//找出到最小生成树节点集合的权值最小的还没入集合的一点 15 if(!vis[j] && (k==-1 || mincost[k]>mincost[j]))k=j; 16 if(k==-1)break;//如果还是-1,表示已经完成最小生成树的建立 17 vis[k]=true;//将节点k纳入最小生成树节点的集合 18 res+=mincost[k];//加上其权值 19 for(int j=1;j<=n;++j)//更新k的邻接点到最小生成树节点集合的最小权值 20 if(!vis[j])mincost[j]=min(mincost[j],cost[k][j]);//还没归纳的节点 21 } 22 return res; 23 } 24 int main() 25 { 26 while(~scanf("%d",&n) && n){ 27 memset(vis,false,sizeof(vis)); 28 for(int i=1;i<=n;++i){ 29 for(int j=1;j<=n;++j) 30 cost[i][j]=(i==j?0:INF); 31 } 32 for(int i=1;i<=n*(n-1)/2;++i){ 33 cin>>a>>b>>c; 34 cost[a][b]=cost[b][a]=c; 35 } 36 printf("%d\n",Prim()); 37 } 38 return 0; 39 }
AC代码之Kruskal: