图的最小生成树----学习的第一个贪心算法prim(普利姆)算法
Prim算法(普里姆算法) :选中任意一个顶点,将其加入到生成树中去(这里假设为顶点1)。用数组记录生成树到各个顶点的距离,每次都是这样。从数组中选出离生成树最近的顶点加入到生成树中(这里用的dijkstra的思想),用dis数组更新为生成树到每一个不在生成树中的顶点的距离(松弛),重复直到有了n个顶点为止。
最近小哼迷上了《龙门镖局》,从恰克图道武夷山,从张家口道老河口,从迪化道佛山,从蒙自道奉天…古代镖局的运镖,也就是现在的物流。镖局每到一个地方开展业务,都需要堆运镖途中的绿林好汉进行打点(不给钱就不让过路)。好说话的打点费就比较低,不好说话的打点费就比较高。城镇类似如下,顶点是城镇编号,边上的值表示这条道路上打点绿林好汉需要的银子数。
请你帮镖局算算,如果从1号城镇出发,遍历每个城镇最少需要准备多少打点银子?
Input
输入第一行包括两个正整数n,m。n代表城镇个数,m表示道路个数(1 < n,m < 100)。
后面的m行分别包含三个正整数a,b,c,表示在从城镇a 到 城镇b的道路上需要交纳的银子数。
Output
输出从1号城镇出发,遍历每个城镇最少需要准备的银子数。
Sample Input
6 9
2 4 11
3 5 13
4 6 3
5 6 4
2 3 6
4 5 7
1 2 1
3 4 9
1 3 2
Sample Output
19
#include<stdio.h>
int main()
{
int n,m,i, j, k, min, t1=0, t2=0, t3=0;
int inf = 99999999;
int e[7][7], dis[7], book[7] = { 0 };
int count = 0, sum = 0;
scanf("%d %d", &n, &m);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n; j++)
{
if(i!=j)
{e[i][j]=inf; }
else
{
e[i][j] = 0;
}
}
}
for (i = 1; i <= m; i++)
{
scanf("%d %d %d", &t1, &t2, &t3);
e[t1][t2] = t3;
e[t2][t1] = t3;
}
for (i = 1; i <= n; i++)
{
dis[i] = e[1][i];
}
book[1] = 1;
count++;
while (count < n)
{
min = inf; //每次都让min=无穷大 很重要
for(i=1;i<=n;i++)
{
if (book[i] ==0 && dis[i] < min)
{
min = dis[i]; //这个for循环一轮结束以后可以找到一个距离生成树最近的顶点(这个顶点被叫做j,同时记录下了它距离生成树的距离dis[j])
j = i;
}
}
book[j] = 1;
sum += dis[j];
count++;
//接下来开始松弛(利用新加入生成树的结点j对所有未加入生成树的结点i进行松弛 (其特征是book[i]==0) )
for (i = 1; i <= n; i++)
{
if (book[i] == 0 && e[j][i] < dis[i])
{
dis[i] = e[j][i]; //这样松弛过后,每个未加入生成树的结点距离生成树的最近距离都求出来了,即dis[j]。
}
}
}
printf("%d", sum);
return 0;
}
这个已经是改进版了,用了数组进行优化。
当然还有更进一步用堆进行优化的
还有最普通的Kruskal算法
下面附上pta上相应题目的链接https://blog.csdn.net/weixin_41707869/article/details/88430827?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160826370216780266222601%252522%25252C%252522scm%252522%25253A%25252220140713.130102334..%252522%25257D&request_id=160826370216780266222601&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-4-88430827.pc_search_result_no_baidu_js&utm_term=%E9%95%96%E5%B1%80%E8%BF%90%E9%95%96