思想:
MST(Minimum Spanning Tree,最小生成树)问题有两种通用的解法,Prim算法就是其中之一,它是从点的方面考虑构建一颗MST,大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。
过程:
http://blog.youkuaiyun.com/yeruby/article/details/38615045
测试用例:
输入:
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
输出:
15
# include <iostream>
# include <cstdio>
# include <cstring>
using namespace std;
# define MAXN 1000
# define INF 0x3f3f3f3f//这个可以与memset(数组名,INF,sizeof(数组名)); 这样可以对数组的全部元素赋值为最大值
int map[MAXN][MAXN],lowcost[MAXN];
bool visit[MAXN];
int n,m,sum;//n节点 m边数 sum保存的是一个城市到另一个城市的最小权值
/*
map保存的是map[a][b] --->a到b的权值
lowcost数组保存的是一个城市到其余的城市的最小的权值
visit保存的是该节点是否被访问过
*/
void prim();
int main(){
int a,b,cost;//a城市到b城市的权值为cost
while(scanf("%d%d",&n,&m)!=EOF){
memset(map,INF,sizeof(map));//map的每一个元素初始化为最大值
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&cost);
if(cost < map[a][b])
map[a][b] = map[b][a] = cost;
}
prim();
printf("%d\n",sum);
}
return 0;
}
void prim(){
int temp,k;
sum = 0;
memset(visit,false,sizeof(visit));//初始化visit 全部为false 证明该节点没有被访问过
visit[1] = true;//说明第一个节点已经被访问过
for(int i=1;i<=n;i++){//对lowcost初始化
lowcost[i] = map[1][i];
}
for(int i=1;i<=n;i++){//找生成树集合点集相连最小权值的边
temp = INF;
for(int j=1;j<=n;j++){//检索没有被访问的城市,而且权值最小的那个城市 ,并保存权值
if(!visit[j] && temp>lowcost[j]){
temp = lowcost[k=j];
}
}
if(temp == INF)//该节点与任何节点没有相连,
break;
visit[k] = true;//把这个城市加入最小生成树集合
sum+=temp; //记录权值之和
for(int j=1;j<=n;j++){//更新lowcost数组
if(!visit[j] && lowcost[j]>map[k][j]){
lowcost[j] = map[k][j];
}
}
}
}