最小生成树(prim)

里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。

 

介绍如下:

http://baike.baidu.com/link?url=nDhHyOlu8i90Hm5bjUycarVdBPN8BXQvnv8NGwl0g4MLlLkmkFLwf7xs1-JBWCRkQw5qDU6cIwh1ov7fyRRxQK

 

原理可以参考这几篇文章:

http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html

http://blog.csdn.net/weinierbian/article/details/8059129

http://blog.chinaunix.net/uid-25324849-id-2182922.html

 

prim算法适合稠密图,邻接矩阵时间复杂度为O(n^2),邻接表为O(eloge),其时间复杂度与边得数目无关。

而kruskal算法的时间复杂度为O(eloge)跟边的数目有关,适合稀疏图。

 

邻接矩阵实现:

  1 #include <iostream>
  2 using namespace std;
  3 
  4 #define MAXVEX 20
  5 #define MAXEDGE 20
  6 #define INFINITY 65535
  7 
  8 
  9 
 10 typedef struct
 11 {
 12           int vexs[MAXVEX];
 13           int arc[MAXVEX][MAXVEX];
 14           int numVertexes,numEdges;
 15 }MGraph;
 16 
 17 typedef int Patharc[MAXVEX];
 18 typedef int ShortPathTable[MAXVEX];
 19 
 20 bool visited[MAXVEX];//保存已访问的数组
 21 int father[MAXVEX];
 22 int closeset[MAXVEX];
 23 
 24 void CreateGraph(MGraph* G)
 25 {
 26           cout<<"请输入边数和顶点数:\n";
 27           int d,n,i,j;
 28           cin>>d>>n;
 29           G->numVertexes = n;
 30           G->numEdges = d;
 31 
 32           //给顶点和边初始化
 33           for(i = 0;i<G->numVertexes;i++)
 34                     G->vexs[i] = i;
 35           for(i = 0;i<G->numVertexes;i++)
 36           {
 37                     for(j = 0;j<G->numVertexes;j++)
 38                     {
 39                               if(i==j)
 40                                         G->arc[i][j] = 0;
 41                               else
 42                                         G->arc[i][j] = G->arc[j][i] = INFINITY;
 43                     }
 44           }
 45 
 46           G->arc[0][1]=1;
 47           G->arc[0][2]=5;
 48           G->arc[1][2]=3;
 49           G->arc[1][3]=7;
 50           G->arc[1][4]=5;
 51 
 52           G->arc[2][4]=1;
 53           G->arc[2][5]=7;
 54           G->arc[3][4]=2;
 55           G->arc[3][6]=3;
 56           G->arc[4][5]=3;
 57 
 58           G->arc[4][6]=6;
 59           G->arc[4][7]=9;
 60           G->arc[5][7]=5;
 61           G->arc[6][7]=2;
 62           G->arc[6][8]=7;
 63 
 64           G->arc[7][8]=4;
 65 
 66           for(i = 0;i<G->numVertexes;i++)
 67           {
 68                     for(j = i;j<G->numVertexes;j++)
 69                     {
 70                               G->arc[j][i] = G->arc[i][j];
 71                     }
 72           }
 73 }
 74 
 75 
 76 int prim(MGraph G, Patharc *P, ShortPathTable *D)
 77 {
 78           int v,w;
 79 
 80           //init
 81           for(v = 0;v<G.numVertexes;v++)
 82           {
 83                     visited[v] = false;
 84                     (*D)[v] = G.arc[0][v];
 85                     father[v] = -1;
 86                     closeset[v] = 0;
 87           }
 88           visited[0] = true;
 89 
 90           int len = 0;
 91           int nlen,nid;
 92 
 93           //求得下一个符合条件的点
 94           for(v = 1;v<G.numVertexes;v++)
 95           {
 96                    nlen = INFINITY;
 97                    for(w = 0;w<G.numVertexes;w++)
 98                    {
 99                              if(!visited[w] && (*D)[w]<nlen)
100                              {
101                                        nlen = (*D)[w];
102                                        nid = w;
103                              }
104                    }
105 
106                    len += nlen;
107                    visited[nid] = true;
108                    father[nid] = closeset[nid];
109 
110                    for(w = 0;w<G.numVertexes;w++)
111                    {
112                              if(!visited[w] && (*D)[w]>G.arc[nid][w])
113                              {
114                                        (*D)[w] = G.arc[nid][w];
115                                        closeset[w] = nid;
116                              }
117                    }
118 
119 
120           }
121 
122           return len;
123 
124 }
125 
126 
127 int main()
128 {
129           int v0,i,j;
130 
131           MGraph G;
132 
133           Patharc P;
134           ShortPathTable D;
135 
136           CreateGraph(&G);
137 
138           int d = prim(G,&P,&D);
139 
140           cout<<"最小树如下:\n";
141           for(i = 1;i<G.numVertexes;i++)
142           {
143                    cout<<"("<<i<<","<<father[i]<<") ";
144           }
145           cout<<endl;
146 
147           cout<<"最短路径长度为:\n";
148 
149           cout<<d<<endl;
150 
151           return 0;
152 
153 
154 }

 

 

我是用vector和pair的邻接表实现的,然后用两个list保存两个集合,一个最小生成树集,一个其他集

实现如下:

  1 #include <iostream>
  2 #include <vector>
  3 #include <queue>
  4 #include <list>
  5 using namespace std;
  6 
  7 vector<pair<int,int> > eg[100];
  8 
  9 vector<pair<int,int> > result;
 10 
 11 typedef pair<int,int> pa;
 12 
 13 bool visit[100];
 14 
 15 list<int> setOfPrim;
 16 
 17 list<int> outOfPrim;
 18 
 19 int lowcost[100] = {0};
 20 
 21 void prim(int n,int d)
 22 {
 23           int min,aim,sta;
 24           bool is;
 25 
 26           list<int>::iterator sop;//最小树集合
 27           list<int>::iterator oop;//其他集合
 28           vector<pair<int,int> >::iterator it;
 29 
 30           setOfPrim.push_back(0);//放入起始点0进最小树集合
 31 
 32           //初始化其他集合
 33           for(int i = 1;i<n;i++)
 34                    outOfPrim.push_back(i);
 35 
 36           while(!outOfPrim.empty())//其他集合不为空
 37           {
 38                     //遍历最小树集合,sop,寻找与集合最近的点
 39                     min = 1<<16;
 40                     for(sop = setOfPrim.begin();sop!=setOfPrim.end();sop++)
 41                     {
 42                               //遍历sop邻接点
 43                               for(int i = 0;i<eg[*sop].size();i++)
 44                               {
 45                                         pa x = eg[*sop][i];
 46                                         is = false;
 47 
 48                                         //如果点属于oop集合
 49                                         for(oop = outOfPrim.begin();oop!=outOfPrim.end();oop++)
 50                                         {
 51                                                   if(*oop == x.first)
 52                                                   {
 53                                                             is = true;
 54                                                   }
 55                                         }
 56 
 57                                         if(is)
 58                                         {
 59                                                   if(x.second<min)
 60                                                   {
 61                                                             min = x.second;
 62                                                             aim = x.first;
 63                                                             sta = *sop;
 64                                                   }
 65                                                   //min存放了离sop集合最近的点的距离
 66                                                   //aim存放了点的序号
 67                                         }
 68                               }
 69                     }
 70 
 71                     setOfPrim.push_back(aim);
 72                     result.push_back(make_pair(sta,aim));
 73                     for(oop = outOfPrim.begin(); oop != outOfPrim.end(); )
 74                     {
 75                               if(*oop == aim)
 76                               {
 77                                         oop = outOfPrim.erase(oop);
 78                                         if(outOfPrim.empty())
 79                                                   break;
 80                               }
 81                               else
 82                                         oop++;
 83                     }
 84                     cout<<"The set of prim:\n";
 85                     for(sop = setOfPrim.begin(); sop != setOfPrim.end();sop++)
 86                     {
 87                               cout<<*sop<<" ";
 88                     }
 89                     cout<<"\nThe set of not prim:\n";
 90                     for(oop = outOfPrim.begin(); oop != outOfPrim.end();oop++)
 91                     {
 92                               cout<<*oop<<" ";
 93                     }
 94                     cout<<endl;
 95 
 96                     for(it = result.begin();it!=result.end();it++)
 97                     {
 98 
 99                               cout<<"("<<(*it).first<<","<<(*it).second<<")";
100                     }
101                     cout<<endl<<endl;
102           }
103 }
104 
105 
106 int main()
107 {
108           int n,d;
109           cin>>n>>d;
110           for(int i = 0;i<d;i++)
111           {
112                     int t,s,w;
113                     cin>>t>>s>>w;
114                     eg[t].push_back(make_pair(s,w));
115                     eg[s].push_back(make_pair(t,w));
116           }
117           prim(n,d);
118 
119 
120 
121 }
122 /*
123 6 8
124 0 1 2
125 0 3 4
126 1 4 4
127 2 0 5
128 2 5 2
129 3 4 3
130 3 5 7
131 5 4 3
132 */

 

另外,因为prim算法和Dijkstra算法很像,这篇文章有讲两者之间的区别:

http://www.cnblogs.com/CheeseZH/archive/2012/10/09/2717106.html

 

posted @ 2015-11-22 23:59  qlky  阅读(606)  评论(0编辑  收藏  举报