题意:
给你N个节点,然后N(N-1)/2即两两点之间的线路, 然后要你求连通所有点的最短路径。即求出最小生成树。
这道题我用prim算法做,prim算法跟Dijkstra还是蛮相似的。代码实现起来也很像。题目没什么困难的地方,算是一道很好的最小生成树的入门题目。
prim算法:
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中,表示该顶点已连通.再用集合内的顶点与集合外的顶点构成的边中找最小的边,并将相应的顶点加入集合中,如此下去直到全部顶点都加入到集合中,即得最小生成树.
例在下图中从1点出发求出此图的最小生成树,并按生成树的边的顺序将顶点与权值填入表中.
详细的可以参考:http://hi.baidu.com/%BA%A3%CF%E0%C1%AC/blog/item/4c5971229671b2549258072a.html
结合代码看看更健康:
#include<iostream> using namespace std; const int Infinity=99999999; const int maxNum=101; int map[maxNum][maxNum]; bool visited[maxNum],nodeNum; int low[maxNum]; int prim()//经典的prim算法 { int result=0,i,j,pos,min; memset(visited,0,sizeof(visited));//visited用来标志结点是否已经入集合 visited[1]=1;//把起始点1标志掉 pos=1; for(i=1;i<=nodeNum;i++) if(i!=pos) { low[i]=map[pos][i];//保存起点到其他点的权值 } for(i=1;i<nodeNum;i++) { min=Infinity; for(j=1;j<=nodeNum;j++) if(!visited[j]&&min>low[j]) { min=low[j];//找出low中的最小值 pos=j; } result+=min;//将此最小值加入生成树中的一员 visited[pos]=1;//把这个pos起点标志掉 for(j=1;j<=nodeNum;j++) if(!visited[j]&&low[j]>map[pos][j])//算出由pos出发到各个未标志的点的权值 low[j]=map[pos][j]; } cout<<result<<endl; return 0; } int main(void) { int s,e,w,i,j; while(scanf("%d",&nodeNum),nodeNum)//输入节点数 { for(i=1;i<=nodeNum;i++) for(j=1;j<=nodeNum;j++) map[i][j]=map[j][i]=Infinity; for(i=1;i<=nodeNum*(nodeNum-1)/2;i++) { scanf("%d%d%d",&s,&e,&w);//起点,终点,权值 map[s][e]=map[e][s]=w; } prim(); } return 0; } |