题目来源 POJ2349
在介绍什么是最小生成树之前先介绍什么是加权图
在之前已经默认了解了无向图(并查集)以及有向无环图(拓扑排序),那么最小生成树可以理解是一个加权的无向图,那么我们要坐的就是在这个无向图中间找出一条路径,使这条路径可以连接所有的结点,并且在所有的情况中,该路径的权值和最小,这一条路径我们称之为最小生成树。(注意一定要区别开最短路)
普里姆算法
简单的说就是从起点开始,不断的从所有点中选出能到达集合V(即为MST的顶点的集合)的最小权值的点,直到这个集合包含了所有的节点,也就是一个贪心过程,集合V指的就是已经被选入为最小生成树的点的集合。
下面看这个题目
首先简单说一下题意,有S个哨所,为了让这S个哨所可以互相联络,有两种方式,一种是通过卫星,这一种比较高级(任意两个拥有卫星频道的哨所可以直接联系,不用管之间的位置关系如何),但是卫星频道只有P个,还有一种就比较低级,就是通过无线电收发器,每个无线电收发器都有限制距离D,D越大,成本越高,也就是说两个哨所越远,就需要功率越大的无线电收发器,那么问题就是求需要的最小的D是多少才能把所有哨所都连接起来(直接或间接)。
理解题意之后我们不难发现,该题的思路就是找到最小生成树,然后并输出权值最长的边就可以了(删去卫星频道之后),每条边的权值即为两点之间的距离。
首先我们需要建图,这里用的是邻接矩阵来建图,但是在普里姆算法中,遍历图的所有顶点来确定D最小的顶点复杂度为O(|V|2)
接下来是代码以及相应的注释
1 #include<iostream> 2 #include<cstring> 3 #include<math.h> 4 #include<queue> 5 #include<iomanip> 6 #include<algorithm> 7 using namespace std; 8 static const double INFTY=(1<<21); 9 static const int BLACK=2;//选定的状态 10 static const int GRAY=1;//候选的状态 11 static const int WHITE=0;//为选择的状态 12 struct stu{int x,y;}len[505]; 13 double dis[505][505];//存两点之间的距离 14 double d[50000];//记录与V连接的顶点的边的最小权值 15 int calor[505];//记录V的访问状态 16 int p[505];//记录MST中顶点v的父节点 17 double minv; 18 priority_queue<double> q; 19 int main() 20 { 21 //freopen("C:\Users\16599\Desktop\in.txt","r",stdin); 22 int T,u; 23 int weixin,state; 24 cin>>T; 25 for(int l=1;l<=T;l++) 26 { 27 memset(dis,0,sizeof(dis)); 28 memset(calor,WHITE,sizeof(calor)); 29 memset(p,-1,sizeof(p)); 30 cin>>weixin>>state; 31 for(int i=1;i<=state;i++) 32 cin>>len[i].x>>len[i].y; 33 for(int i=1;i<state;i++) 34 for(int j=i+1;j<=state;j++) 35 dis[i][j]=dis[j][i]=sqrt((len[j].x-len[i].x)*(len[j].x-len[i].x)+(len[j].y-len[i].y)*(len[j].y-len[i].y)); 36 for(int i=1;i<=state;i++) 37 d[i]=INFTY;//建图的过程 38 d[1]=0;//选定起点 39 while(true) 40 { 41 minv=INFTY; 42 u=-1; 43 for(int i=1;i<=state;i++)//找到连接集合V权值最小的点 44 { 45 if(minv>d[i]&&calor[i]!=BLACK) 46 { 47 u=i; 48 minv=d[i]; 49 //cout<<minv<<" "<<i<<endl; 50 } 51 } 52 if(u==-1)//MST已建成,结束 53 { 54 break; 55 } 56 calor[u]=BLACK;//将选好的点加入到V中 57 for(int v=1;v<=state;v++)//更新连接V的所有点的状态以及最小权值 58 { 59 if(calor[v]!=BLACK&&dis[u][v]!=INFTY) 60 { 61 if(d[v]>dis[u][v]) 62 { 63 d[v]=dis[u][v]; 64 p[v]=u; 65 calor[v]=GRAY; 66 } 67 } 68 } 69 while(!q.empty())//更新MST 70 q.pop(); 71 for(int i=1;i<=state;i++) 72 if(p[i]!=-1) 73 q.push(dis[i][p[i]]); 74 } 75 while(1) 76 { 77 if(weixin==1) 78 break; 79 weixin--; 80 q.pop(); 81 } 82 cout<<fixed<<setprecision(2)<<q.top()<<endl; 83 } 84 return 0; 85 }