最小生成树(prim)

时间:2023-12-21 12:48:56

里姆算法(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)跟边的数目有关,适合稀疏图。

邻接矩阵实现:

 #include <iostream>
using namespace std; #define MAXVEX 20
#define MAXEDGE 20
#define INFINITY 65535 typedef struct
{
int vexs[MAXVEX];
int arc[MAXVEX][MAXVEX];
int numVertexes,numEdges;
}MGraph; typedef int Patharc[MAXVEX];
typedef int ShortPathTable[MAXVEX]; bool visited[MAXVEX];//保存已访问的数组
int father[MAXVEX];
int closeset[MAXVEX]; void CreateGraph(MGraph* G)
{
cout<<"请输入边数和顶点数:\n";
int d,n,i,j;
cin>>d>>n;
G->numVertexes = n;
G->numEdges = d; //给顶点和边初始化
for(i = ;i<G->numVertexes;i++)
G->vexs[i] = i;
for(i = ;i<G->numVertexes;i++)
{
for(j = ;j<G->numVertexes;j++)
{
if(i==j)
G->arc[i][j] = ;
else
G->arc[i][j] = G->arc[j][i] = INFINITY;
}
} G->arc[][]=;
G->arc[][]=;
G->arc[][]=;
G->arc[][]=;
G->arc[][]=; G->arc[][]=;
G->arc[][]=;
G->arc[][]=;
G->arc[][]=;
G->arc[][]=; G->arc[][]=;
G->arc[][]=;
G->arc[][]=;
G->arc[][]=;
G->arc[][]=; G->arc[][]=; for(i = ;i<G->numVertexes;i++)
{
for(j = i;j<G->numVertexes;j++)
{
G->arc[j][i] = G->arc[i][j];
}
}
} int prim(MGraph G, Patharc *P, ShortPathTable *D)
{
int v,w; //init
for(v = ;v<G.numVertexes;v++)
{
visited[v] = false;
(*D)[v] = G.arc[][v];
father[v] = -;
closeset[v] = ;
}
visited[] = true; int len = ;
int nlen,nid; //求得下一个符合条件的点
for(v = ;v<G.numVertexes;v++)
{
nlen = INFINITY;
for(w = ;w<G.numVertexes;w++)
{
if(!visited[w] && (*D)[w]<nlen)
{
nlen = (*D)[w];
nid = w;
}
} len += nlen;
visited[nid] = true;
father[nid] = closeset[nid]; for(w = ;w<G.numVertexes;w++)
{
if(!visited[w] && (*D)[w]>G.arc[nid][w])
{
(*D)[w] = G.arc[nid][w];
closeset[w] = nid;
}
} } return len; } int main()
{
int v0,i,j; MGraph G; Patharc P;
ShortPathTable D; CreateGraph(&G); int d = prim(G,&P,&D); cout<<"最小树如下:\n";
for(i = ;i<G.numVertexes;i++)
{
cout<<"("<<i<<","<<father[i]<<") ";
}
cout<<endl; cout<<"最短路径长度为:\n"; cout<<d<<endl; return ; }

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

实现如下:

 #include <iostream>
#include <vector>
#include <queue>
#include <list>
using namespace std; vector<pair<int,int> > eg[]; vector<pair<int,int> > result; typedef pair<int,int> pa; bool visit[]; list<int> setOfPrim; list<int> outOfPrim; int lowcost[] = {}; void prim(int n,int d)
{
int min,aim,sta;
bool is; list<int>::iterator sop;//最小树集合
list<int>::iterator oop;//其他集合
vector<pair<int,int> >::iterator it; setOfPrim.push_back();//放入起始点0进最小树集合 //初始化其他集合
for(int i = ;i<n;i++)
outOfPrim.push_back(i); while(!outOfPrim.empty())//其他集合不为空
{
//遍历最小树集合,sop,寻找与集合最近的点
min = <<;
for(sop = setOfPrim.begin();sop!=setOfPrim.end();sop++)
{
//遍历sop邻接点
for(int i = ;i<eg[*sop].size();i++)
{
pa x = eg[*sop][i];
is = false; //如果点属于oop集合
for(oop = outOfPrim.begin();oop!=outOfPrim.end();oop++)
{
if(*oop == x.first)
{
is = true;
}
} if(is)
{
if(x.second<min)
{
min = x.second;
aim = x.first;
sta = *sop;
}
//min存放了离sop集合最近的点的距离
//aim存放了点的序号
}
}
} setOfPrim.push_back(aim);
result.push_back(make_pair(sta,aim));
for(oop = outOfPrim.begin(); oop != outOfPrim.end(); )
{
if(*oop == aim)
{
oop = outOfPrim.erase(oop);
if(outOfPrim.empty())
break;
}
else
oop++;
}
cout<<"The set of prim:\n";
for(sop = setOfPrim.begin(); sop != setOfPrim.end();sop++)
{
cout<<*sop<<" ";
}
cout<<"\nThe set of not prim:\n";
for(oop = outOfPrim.begin(); oop != outOfPrim.end();oop++)
{
cout<<*oop<<" ";
}
cout<<endl; for(it = result.begin();it!=result.end();it++)
{ cout<<"("<<(*it).first<<","<<(*it).second<<")";
}
cout<<endl<<endl;
}
} int main()
{
int n,d;
cin>>n>>d;
for(int i = ;i<d;i++)
{
int t,s,w;
cin>>t>>s>>w;
eg[t].push_back(make_pair(s,w));
eg[s].push_back(make_pair(t,w));
}
prim(n,d); }
/*
6 8
0 1 2
0 3 4
1 4 4
2 0 5
2 5 2
3 4 3
3 5 7
5 4 3
*/

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

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