1.题目:
最小生成树
从昆明LTE网络中,选取部分基站,计算基站间的距离,在部分基站间引入边,得到
1)22个基站顶点组成的图
2)42个基站顶点组成的图
最小生成树
生成这2个图的最小生成树
要求:
采用K算法,或P算法;
给出最小生成树的成本/代价/耗费cost
做图,呈现出最小生成树,
可以在原图上,用红色、粗线条,标记最小生成树的边
从昆明LTE网络中,选取部分基站,计算基站间的距离,在部分基站间引入边,得到
1)22个基站顶点组成的图
2)42个基站顶点组成的图
最小生成树
生成这2个图的最小生成树
要求:
采用K算法,或P算法;
给出最小生成树的成本/代价/耗费cost
做图,呈现出最小生成树,
可以在原图上,用红色、粗线条,标记最小生成树的边
----------------------------------------------------------------
2.Prim 算法
1) 算法思想:采用集合存储法,由于Prim算法是对点的选择,从某一个点开始,选择
到该点的最小边所对应的定点,加入到确定集合中,然后再在确定集合里找到非确定
点集合的最小边,再加入到确定点集合里依次类推,直到所有的点都加入到确定点集合中,*/
1) 算法思想:采用集合存储法,由于Prim算法是对点的选择,从某一个点开始,选择
到该点的最小边所对应的定点,加入到确定集合中,然后再在确定集合里找到非确定
点集合的最小边,再加入到确定点集合里依次类推,直到所有的点都加入到确定点集合中,*/
2)算法代码:
#include<iostream> #include<fstream> #define BASE_NUM1 22 #define BASE_NUM2 42 #define INIF 999999999 struct BRANCH{ int x; int y; double weight; }; int ID[BASE_NUM2+1];//基站编号 BRANCH branch[BASE_NUM2]; //记录最小生成树有哪些边加入其中了,共有n-1条边加入其中 int book[BASE_NUM2+1];//标记数组,=0表示未加入确定集,=1表示加入确定集 double graph[BASE_NUM2+1][BASE_NUM2+1]; //存储地图 double min_weight; //生成树的最小权值 void Prim(int base_num); void Out_Min_Tree(int base_num); using namespace std; int main() { system("color 0B"); fstream file; /******对文件一的处理**********************/ file.open("图22.txt",ios::in); if(!file) { cout<<"图22打开失败!";exit(1); } int i,j; double temp; //写入数据 for(i=1;i<=BASE_NUM1;i++) file>>ID[i]; for(i=1;i<=BASE_NUM1;i++) { file>>temp; for(j=1;j<=BASE_NUM1;j++) { file>>temp; graph[i][j]=(temp<0.0)?INIF:temp; } } //Prim算法求最小生成树 Prim(BASE_NUM1); cout<<"(Prim算法)图一最小生成树所包含的边为:"<<endl; Out_Min_Tree(BASE_NUM1); //输出最小生成树 cout<<"最小生成树的成本="<<min_weight<<endl; file.close(); /******对文件二的处理**********************/ min_weight=0; file.open("图42.txt",ios::in); if(!file) { cout<<"图42打开失败!";exit(1); } //写入数据 for(i=1;i<=BASE_NUM2;i++) file>>ID[i]; for(i=1;i<=BASE_NUM2;i++) { file>>temp; for(j=1;j<=BASE_NUM2;j++) { file>>temp; graph[i][j]=(temp<0.0)?INIF:temp; } } //Prim算法求最小生成树 Prim(BASE_NUM2); cout<<"(Prim算法)图二最小生成树所包含的边为:"<<endl; Out_Min_Tree(BASE_NUM2); //输出最小生成树 cout<<"最小生成树的成本="<<min_weight<<endl; return 0; } void Prim(int base_num) { int have[base_num+1],i,j,k; //已经加入的集合 double min_edge; int start,end; //初始化 for(i=1;i<=base_num;i++) book[i]=0; book[1]=1;//从编号为1的顶点开始构造 have[1]=1; //第一个定点入确定集合集合 for(i=1;i<base_num;i++) { min_edge=INIF; for(j=1;j<=i;j++) //在确定集里找 { for(k=1;k<=base_num;k++) { if(book[k]==0&&min_edge>graph[have[j]][k]) { start=have[j]; end=k; min_edge=graph[start][end]; } } } branch[i].x=start; branch[i].y=end; branch[i].weight=min_edge; min_weight+=min_edge; book[end]=1; have[i+1]=end; } } void Out_Min_Tree(int base_num) { int i; cout<<"起点位置:\t"<<"终点位置:\t"<<"边权\t"<<endl; for(i=1;i<base_num;i++) { cout<<branch[i].x<<"\t\t"<<branch[i].y<<"\t\t"<<branch[i].weight<<endl; } }
---------------------------------------------------------------------
2.Kruskal算法实现
1)算法思想:由K算法的出发点可知,第一:对边实现最小性选择,第二,不能成环。
对于第一点:将边的信息按权值从小到大排序,再进行选择;对于第二点:采用并查集思想,一旦一条边能够加入加入到某一个集合内,将该集合的边的所有顶点的标记置成相同的值,表示一类,直到选择了n-1条边为止。
2)代码实现
#include<iostream> #include<fstream> #include<algorithm> #include<math.h> #define BASE_NUM1 22 #define BASE_NUM2 42 #define INIF 999999999 #define MAX_EDGE 10000 using namespace std; /*并查集方法,将边*/ int ID[BASE_NUM2+1];//基站编号 double graph[BASE_NUM2+1][BASE_NUM2+1]; //存储地图 double min_weight; //生成树的最小权值 struct EDGE{ int start; int end; double weight; }; EDGE edge[MAX_EDGE]; //存储原图中的边的集合 EDGE branch[BASE_NUM2+1]; //存储选定的树中的边 void Kruskal(int base_num,int edge_num); void Out_Min_Tree(int base_num); int cmp(EDGE&a, EDGE&b) { return a.weight<b.weight; } int main() { system("color 0B"); fstream file; /******对文件一的处理**********************/ file.open("图22.txt",ios::in); if(!file) { cout<<"图22打开失败!";exit(1); } int i,j,sum_edge=0; double temp; for(i=1;i<=BASE_NUM1;i++) file>>ID[i]; for(i=1;i<=BASE_NUM1;i++) { file>>temp; for(j=1;j<=BASE_NUM1;j++) { file>>temp; graph[i][j]=(temp<0.0)?INIF:temp; if(i<j&&temp>0) { edge[sum_edge].start=i; edge[sum_edge].end=j; edge[sum_edge].weight=temp; sum_edge++; } } } //对边的集合进行从小到大排序 sort(edge,edge+sum_edge,cmp); Kruskal(BASE_NUM1,sum_edge); cout<<"(Kruskal算法)图一最小生成树所包含的边为:"<<endl; Out_Min_Tree(BASE_NUM1); //输出最小生成树 cout<<"最小生成树的成本="<<min_weight<<endl; file.close(); /******对文件二的处理**********************/ sum_edge=0; min_weight=0; file.open("图42.txt",ios::in); if(!file) { cout<<"图42打开失败!";exit(1); } for(i=1;i<=BASE_NUM2;i++) file>>ID[i]; for(i=1;i<=BASE_NUM2;i++) { file>>temp; for(j=1;j<=BASE_NUM2;j++) { file>>temp; graph[i][j]=(temp<0.0)?INIF:temp; if(i<j&&temp>0) { edge[sum_edge].start=i; edge[sum_edge].end=j; edge[sum_edge].weight=temp; sum_edge++; } } } //对边的集合进行从小到大排序 sort(edge,edge+sum_edge,cmp); Kruskal(BASE_NUM2,sum_edge); cout<<"(Kruskal算法)图一最小生成树所包含的边为:"<<endl; Out_Min_Tree(BASE_NUM2); //输出最小生成树 cout<<"最小生成树的成本="<<min_weight<<endl; return 0; } void Kruskal(int base_num,int edge_num) { int i,j,m1,m2,sn1,sn2,count; int v_set[base_num+1]; //初始化铺助数组 for(i=1;i<=base_num;i++) v_set[i]=i; count=1;//count表示当前构造最小生成树的第几条边 j=0; //边集的下标 while(count<base_num) { m1=edge[j].start;sn1=v_set[m1]; m2=edge[j].end;sn2=v_set[m2]; if(sn1!=sn2) //加入生成树边的集合中 关键条件,保证不会形成一个环 { branch[count]=edge[j]; min_weight+=branch[count].weight; count++; for(i=1;i<=base_num;i++) if(v_set[i]==sn2) //集合编号为sn2的改成sn1 v_set[i]=sn1; } j++; //扫描下一条边 } } void Out_Min_Tree(int base_num) { int i; cout<<"起点位置:\t"<<"终点位置:\t"<<"边权\t"<<endl; for(i=1;i<base_num;i++) { cout<<branch[i].start<<"\t\t"<<branch[i].end<<"\t\t"<<branch[i].weight<<endl; } }