里姆算法(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<<"请输入边数和顶点数: "; 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<<"最小树如下: "; 141 for(i = 1;i<G.numVertexes;i++) 142 { 143 cout<<"("<<i<<","<<father[i]<<") "; 144 } 145 cout<<endl; 146 147 cout<<"最短路径长度为: "; 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: "; 85 for(sop = setOfPrim.begin(); sop != setOfPrim.end();sop++) 86 { 87 cout<<*sop<<" "; 88 } 89 cout<<" The set of not prim: "; 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