最小生成树之Prim的应用
现在是凌晨时分 本来很早就想写了 被一道搜索题卡到现在 至今没有A出 等A出以后 一定要写出来 ....
Prim:它是 基于 图的顶点 的算法
其实 这个算法 是很容易理解的
首先 你任意选取一个点 加入MST集合中 这里的MST即最小生成树集合
然后你对所有不属于MST的点 进行循环遍历寻找权值最小的边
并且 再每加入一个点后 就刷新其余点到这个MST集合的相对最短距离(这是核心步骤)
个人 感觉Prim算法 还是很基础的 当你不考虑heap优化的情况下
我们还是 那道题说说吧
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=38
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <stdio.h> 2 #include <string.h> 3 #define MAX 100000000 4 int map[505][505];//邻接矩阵 5 int dis[505];//距离 并且指这条边是以dis[i]的i为结尾的 6 int visited[505]; 7 int n,m; 8 9 int prim() 10 { 11 int i,j,k,ans=0,min,t; 12 memset(visited,0,sizeof(visited));//起初标记所有点都未被访问 13 for(i=1;i<=n;i++) 14 dis[i]=map[1][i];//所有最小权值边起初都是以相同的起始点1开始 15 visited[1]=1;//从1开始访问 16 for(i=1;i<n;i++)//因为是最小生成树 所以当有n个顶点的时候 只有n-1条边 17 { 18 min=MAX;//将Min设置的 无穷大 以便来标记 19 for(j=2;j<=n;j++) 20 { 21 if( !visited[j] && dis[j]<min )//j的要求未被访问 并且可以得到相对最小距离 22 { 23 min=dis[j]; 24 t=j; 25 } 26 } 27 if(min==Max)//如果这个if成立相当于 上面没有一个j进入MST中 所有可以直接break 28 break; 29 ans+=min; 30 visited[t]=1; 31 32 for(k=2;k<=n;k++) 33 { 34 if( !visited[k] && dis[k]> map[t][k] )//这边 我用大于号 才能刷新最下值 35 dis[k]=map[t][k]; 36 } 37 38 } 39 return ans; 40 } 41 42 int main() 43 { 44 int t,a,b,c,i,j,min; 45 scanf("%d",&t); 46 while (t--) 47 { 48 scanf("%d %d",&n,&m); 49 for(i=1;i<=n;i++) 50 { 51 for(j=1;j<=n;j++) 52 map[i][j]=MAX; 53 } 54 for(i=1;i<=m;i++) 55 { 56 scanf("%d%d%d",&a,&b,&c); 57 map[a][b]=map[b][a]=c; 58 } 59 min=MAX; 60 for(i=1;i<=n;i++) 61 { 62 scanf("%d",&a); 63 if(a<min) 64 min=a; 65 } 66 printf("%d\n",min+prim()); 67 } 68 }
这边 我给出的是邻接矩阵的实现方式 你可以自己去实现 邻接表的方式 而我会在下次 讲到欧拉图的时候 使用邻接表
其实 这段以前写过的代码 还有很多可以优化的细节 例如:vis数组 用bool实现 MAX的设置使用16进制来实现
我还想提的一点是: Prim算法的思想 与 最短路中Dijkstra的思想 实在是太像了
最大的区别就是:Dijk数组含义上的不同:这里是指顶点到MST集合的最短距离 Dijkstra算法中是指顶点到起始点的最短距离
我想 对于每个算法 了解它的思想 才是最重要的
just follow your heart