也是一个很好的贪心的程序,
具体看代码:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <string>
/*
*这是用Prim来解决Minimal Spanning Tree的问题,
*当然Kruskal和Prim都是利用的贪心思想,而Kruskal更是将贪心的思想体现的淋漓尽致,,
*但是Prim也是不错的想法,
*思想的主要特征就是随机选取一个点作为起点a,(一般选取第一个点做为起点)然后选取距离
*此点的权值最小的点b,更新这个点的权值dis[b],当然要标记a这个点已经访问vis[i] = 1,
*然后每次找到最小的dis值,做为起点,找寻距离此点最小的下一个邻接点,并且更新它.
*当最后全部更新完毕的时候就结束后了一共需要进行
*/
using namespace std;
const int INF = 0x3f3f3f3f; // 定义int型的最大值INF 相当于正无穷,当然定义成0x3f3f3f3f应该也可以解决这个问题,
//但是不够严密;
int N;
int M;
int map[105][105];
int vis[105];
int dis[105];
void Init()
{
memset(map, 0x3f, sizeof(map));//其实这样是不是很好的,因为0x3f3f3f3f并不是真正意义上的正无穷,不过
//由于memset的效率比较高,还是比较倾向于这样赋值;
/*
for (int i = 0; i < 105; i++)
{
for (int j = 0; j < 105; j++)
{
map[i][j] = INF;
}
} // 用了for循环来赋值,也是15ms,好像体现不出优越性呀,,,,诶,,
*/
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= N; i++)
{
dis[i] = INF;
map[i][i] = 0; // 其实这个也是有必要的,自己距离自己的权值是0;
}
}
int Prim()
{
dis[1] = 0;
for (int i = 1; i <= N; i++) // 其实可以不用运行N次, 只用到N-1次的时候就已经把所有的边都存到dis中了
{
int t = INF;
int pos;
for (int j = 1; j <= N; j++)
{
if (!vis[j] && t > dis[j])//用t来筛选出此时没有被访问,并且dis的值最小的点
{
t = dis[j];
pos = j;
}
}
vis[pos] = 1;//标记这个点已经被访问了
for (int j = 1; j <= N; j++)
{
if (!vis[j] && map[pos][j] != 0x3f3f3f3f && dis[j] > map[pos][j])//首先
//需要满足的就是与pos向邻接,并且dis存的值需要更新的时候才执行
{
dis[j] = map[pos][j];
}
}
}
int sum = 0;
for (int i = 1; i <= N; i++)
{
sum += dis[i];//把所有的dis值都加上,就是所求的最小生成树的解
}
return sum;
}
int main()
{
while (scanf("%d%d", &N, &M) != EOF)
{
Init();
int a, b, val;
for (int i = 1; i <= M; i++)
{
scanf("%d%d%d", &a, &b, &val);
if (map[a][b] > val)//其实这一步还是有必要的,判断,当有重边的时候,可以选取边最小的val,不多余;
{
map[a][b] = val;
map[b][a] = val;
}
}
int ans = Prim();
printf("%d\n", ans);
}
return 0;
}