prim算法

最小生成树

   一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。

 

  普里姆算法(Prim算法)

图例所示:

1)图中有6个顶点v1-v6,每条边的边权值都在图上;在进行prim算法时,我先随意选择一个顶点作为起始点,当然我们一般选择v1作为起始点,好,现在我们设U集合为当前所找到最小生成树里面的顶点,TE集合为所找到的边,现在状态如下:

U={v1}; TE={};

(2)现在查找一个顶点在U集合中,另一个顶点在V-U集合中的最小权值,如下图,在红线相交的线上找最小值。

 

                                             

 

 通过图中我们可以看到边v1-v3的权值最小为1,那么将v3加入到U集合,(v1,v3)加入到TE,状态如下:

U={v1,v3}; TE={(v1,v3)};

(3)继续寻找,现在状态为U={v1,v3}; TE={(v1,v3)};在与红线相交的边上查找最小值。

                                                    

 

我们可以找到最小的权值为(v3,v6)=4,那么我们将v6加入到U集合,并将最小边加入到TE集合,那么加入后状态如下:

U={v1,v3,v6}; TE={(v1,v3),(v3,v6)}; 如此循环一下直到找到所有顶点为止。

(4)下图像我们展示了全部的查找过程:

                                 

相关题目:

       题目描述:
    某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。
 
 
输入:

    测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
    当N为0时,输入结束,该用例不被处理。

输出:

    对每个测试用例,在1行里输出最小的公路总长度。

样例输入:
3
1 2 1
1 3 2
2 3 4
4
1 2 1
1 3 4
1 4 1
2 3 3
2 4 2
3 4 5
0
样例输出:

3

5

实现算法(c++):
//Prim Algorithm
#include <iostream>
#include <fstream>
#include <cstring>
#include <queue>
#define CITY 101
#define INFINITE 0x7fffffff
using namespace std;
int dist[CITY][CITY];
int flag[CITY];
int cityNum;
int prim();
int visitedCount();
int main()
{
        //ifstream cin("input.txt");
        int i;
        while(cin>>cityNum)
        {
                if(cityNum==0)
                break;
                memset(dist,0,sizeof(dist));
                memset(flag,0,sizeof(flag));
                int terA,terB,distance;
                for(i=0;i<(cityNum*(cityNum-1)/2);i++)
                {
                        cin>>terA>>terB>>distance;
                        dist[terA][terB]=distance;
                        dist[terB][terA]=distance;
                }
                cout<<prim()<<endl;
        }
}

int prim()
{
        int i,j;
        int newBegin,newEnd;
        int allDistance=0;
        flag[1]=1;
        while(visitedCount()<cityNum)
        {
                int min=INFINITE;
                for(i=1;i<=cityNum;i++)
                {
                        if(flag[i]==1)
                        {
                                for(j=1;j<=cityNum;j++)
                                {
                                        if(flag[j]==0)
                                        if(dist[i][j]<min)
                                        {
                                                min=dist[i][j];
                                                newBegin=i;
                                                newEnd=j;
                                        }
                                }
                        }
                }
                flag[newEnd]=1;
                allDistance+=dist[newBegin][newEnd];
        }
        return allDistance;
}

int visitedCount()
{
        int i,sum=0;
        for(i=1;i<=cityNum;i++)
        if(flag[i]==1)
        sum++;
        return sum;
}


算法解析:
dist是二维数组,第i行第j列存储着第i个城市到第j个城市的距离。dist是一个对称矩阵。
cityNum是城市的数量;
用一个flag数组来存储每个城市是否已经被加入最小生成树中。
对于已经加入最小生成树的节点,其在flag数组中对应的项为1;


当加入树的节点的个数小于citynumber时
循环
将最小值清0;
{
对每个生成树中的城市i
{
在其他城市(未加入生成树)与第i个城市的距离中挑选最小值;
记录最小值
记录最小值对应的起始城市i;
记录最小值对应的终点城市j;
}
将城市j加入生成树;
最短距离+最小值成为新的最短距离;
}

 

 

 

 

posted @ 2016-03-22 14:36  cancanw  阅读(587)  评论(0编辑  收藏  举报