Prim算法求解最小生成树
- 格式:doc
- 大小:161.00 KB
- 文档页数:9
Prim算法求解最小生成树
1.最小生成树问题描述
在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树。
最小生成树其实是最小权重生成树的简称。
2.Prim算法思想
大致思想是:设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗最小生成树。
因为有N个顶点,所以该MST就有N-1条边,每一次向集合V 中加入一个点,就意味着找到一条最小生成树的边。
3.Prim算法描述(步骤)
1.首先,初始化图G,并构建好无向图
for (i = 1; i <= m; i++)
{
for (j = 1; j <= m; j++)
{
graph[i][j] = MAXCOST;
}
}
for (k = 1; k <= n; k++)
{
scanf("%d %d %d",&i,&j,&cost);
graph[i][j] = cost;
graph[j][i] = cost;
}
2.再利用Prim算法来求解得到最小生成树
默认起点是1
for (i = 2; i <= n; i++)
{
lowcost[i] = graph[1][i];
mst[i] = 1;
}
找出距离1最近的点
for (j = 2; j <= n; j++)
{
if (lowcost[j] < min && lowcost[j] != 0)
{
min = lowcost[j];
minid = j;
}
}
4.算法实现(数据结构)
设置2个数据结构:
所有点默认起点是V1
lowcost[i]:表示以i为终点的边的最小权值,当lowcost[i]=0说明以i为终点的边的最小权值=0,也就是表示i点加入了最小生成树
mst[i]:表示对应lowcost[i]的起点,即说明边<mst[i],i>是最小生成树的一条边,当mst[i]=0表示起点i加入最小生成树
for (j = 2; j <= n; j++)
{
if (graph[minid][j] < lowcost[j])
//比较最小生成树外部的点到minid的距离或到之前的最小生成树里点的距离大小,更新lowcost[j]取最小值
{
lowcost[j] = graph[minid][j];
mst[j] = minid;
//点j到最小生成树内的lowcost对应的最小生成树里的点是minid
}
} //相当于利用mind作为新的起点来更新lowcost[];
5.实验环境
硬件环境:WIN10系统笔记本
软件环境:Visual C++ 6.0
6.、实验结果
运行结果:
问题规模:
由算法代码中的循环嵌套可得知此算法的时间复杂度为O(n^2)。
运行时间:
7.附录(源程序代码)
#include<iostream>
#include<fstream>
#include<ctime>
using namespace std;
#define MAX 100
#define MAXCOST 0x7fffffff
int graph[MAX][MAX];
//Prim算法
int prim(int graph[][MAX], int n)
{
int lowcost[MAX];
int mst[MAX];
int i, j, min, minid, sum = 0;
for (i = 2; i <= n; i++)
{
lowcost[i] = graph[1][i]; //lowcost[i]:表示以i为终点的边的最小权值
mst[i] = 1; //mst[]存放最小生成树外的点i到最小生成树最短距离时候对应的最小生成树里的点标号
}
mst[1] = 0; //当mst[i]=0表示起点i加入最小生成树
for (i = 2; i <= n; i++) //要找出n-1个点为止
{
min = MAXCOST;
minid = 0;
for (j = 2; j <= n; j++)
{
if (lowcost[j] < min && lowcost[j] != 0)
{
min = lowcost[j];
minid = j;
}
}
printf("v%d-v%d=%d\n",mst[minid],minid,min);
sum += min;
lowcost[minid] = 0; //当lowcost[i]=0说明以i为终点的边的最小权值=0,也就是表示i点加入了最小生成树
for (j = 2; j <= n; j++)
{
if (graph[minid][j] < lowcost[j]) //比较最小生成树外部的点到minid的距离或到之前的最小生成树里点的距离大小,更新lowcost[j]取最小值
{
lowcost[j] = graph[minid][j];
mst[j] = minid; //点j到最小生成树内的lowcost对应的最小生成树里的点是minid
}
}
}
return sum;
}
int main()
{
clock_t startTime,endTime;
int i, j, k, m, n;
int cost;
printf("请输入顶点数和边数(m n):\n");
scanf("%d %d",&m,&n); //m=顶点的个数,n=边的个数
//初始化图G
for (i = 1; i <= m; i++)
{
for (j = 1; j <= m; j++)
{
graph[i][j] = MAXCOST;
}
}
//构建图G
printf("请输入权值边对应的顶点和权值(i j w):\n");
for (k = 1; k <= n; k++)
{
scanf("%d %d %d",&i,&j,&cost);
graph[i][j] = cost;
graph[j][i] = cost; //对称
}
//求解最小生成树
startTime = clock();//计时开始
cost = prim(graph, m);
//输出最小权值和
printf("最小权值和=%d\n",cost);
endTime = clock();//计时结束
cout << "The run time is:" <<(double)(endTime - startTime) / CLOCKS_PER_SEC << "s" << endl;
system("pause");
return 0;
}。