首先解释什么是最小生成树,最小生成树是指在一张图中找出一棵树,任意两点的距离已经是最短的了。
算法要点:
1、用book数组存放访问过的节点。
2、用dis数组保存对应下标的点到树的最近距离,这里要注意,是对树最近的距离,而不是源点,这和单源最短路径是有区别的。
3、用maps数组保存边的关系。
4、每次先找到离树最近的且没有被访问过的点,以这点的所有边去更新dis数组,也就是更新和树的最近距离。
算法模型:
for(循环n-1次,因为默认1点为起始点,已经被访问了)
{
for(循环n次。)
{
利用book数组,找到dis中的最近点,且没被访问过的点。
}
记录该点被访问,记录当前dis该点的距离存放至答案。
for(循环n次)
{
利用book数组,找到没有被访问过的点,用该点的所有边更新dis数组,也就是更新和树的最近距离。
}
}
#include<cstdio> #include<cstdlib> #include<iostream> using namespace std; /*最小生成树Prim未优化版*/ int book[100];//用于记录这个点有没有被访问过 int dis[100];//用于记录距离树的距离最短路程 int MAX = 99999;//边界值 int maps[100][100];//用于记录所有边的关系 int main() { int i,j,k;//循环变量 int n,m;//输入的N个点,和M条边 int x,y,z;//输入变量 int min,minIndex; int sum=0;//记录最后的答案 cin>>n>>m; //初始化maps,除了自己到自己是0其他都是边界值 for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { if(i!=j) maps[i][j] = MAX; else maps[i][j] = 0; } } for (i = 1; i <= m; i++) { cin>>x>>y>>z;//输入的为无向图 maps[x][y] = z; maps[y][x] = z; } //初始化距离数组,默认先把离1点最近的找出来放好 for (i = 1; i <= n; i++) dis[i] = maps[1][i]; book[1]=1;//记录1已经被访问过了 for (i = 1; i <= n-1; i++)//1已经访问过了,所以循环n-1次 { min = MAX;//对于最小值赋值,其实这里也应该对minIndex进行赋值,但是我们承认这个图一定有最小生成树而且不存在两条相同的边 //寻找离树最近的点 for (j = 1; j <= n; j++) { if(book[j] ==0 && dis[j] < min) { min = dis[j]; minIndex = j; } } //记录这个点已经被访问过了 book[minIndex] = 1; sum += dis[minIndex]; for (j = 1; j <= n; j++) { //如果这点没有被访问过,而且这个点到任意一点的距离比现在到树的距离近那么更新 if(book[j] == 0 && maps[minIndex][j] < dis[j]) dis[j] = maps[minIndex][j]; } } cout<<sum<<endl; } /* 6 9 2 4 11 3 5 13 4 6 3 5 6 4 2 3 6 4 5 7 1 2 1 3 4 9 1 3 2 Result:19 */
以上这个算法是没有优化过的,优化的方法很多,堆排序,邻接表等等。有兴趣可以继续看看。
主要想说的是最小生成树和单源最短路径是有区别的,虽然看起来代码比较像,但是本质有些不同,看到题目的时候,还是要好好去分析使用什么方法去做。