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;
}
}