题意:
要求你输入n条边,还有nodeNum个结点。
然后求将所有结点连接起来的总权值达到最小,这不就是最小生成树嘛。题意还是比较经典,好理解的。
prim算法:
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的所有边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中,表示该顶点已连通.再用集合内的顶点与集合外的顶点构成的边中找最小的边,并将相应的顶点加入集合中,如此下去直到全部顶点都加入到集合中,即得最小生成树.
例在下图中从1点出发求出此图的最小生成树,并按生成树的边的顺序将顶点与权值填入表中.
详细的可以参考:http://hi.baidu.com/%BA%A3%CF%E0%C1%AC/blog/item/4c5971229671b2549258072a.html
结合代码看看:
/* 又是变量写错,j写成了i,最近怎么了 */ #include<iostream> using namespace std; const int Infinity=9999999; const int maxNum=105; int map[maxNum][maxNum]; bool visited[maxNum];//标志点是否入已经集合 int low[maxNum],nodeNum;//结点 int prim() { int result,i,j,min,pos=1;//pos=1表示从点1开始 memset(visited,0,sizeof(visited)); result=0; for(i=1;i<=nodeNum;i++) low[i]=map[pos][i]; visited[pos]=1; for(i=1;i<nodeNum;i++) { min=Infinity,pos=-1; for(j=1;j<=nodeNum;j++) if(!visited[j]&&min>low[j]) { min=low[j]; pos=j; } if(pos==-1)//如果pos等于-1,证明没有点可以入集,那么最下生成树不能完成 return -1; visited[pos]=1;//pos点标志掉 result+=min; for(j=1;j<=nodeNum;j++) if(!visited[j]&&low[j]>map[pos][j]) low[j]=map[pos][j];//这里的j写成了i,擦,改了半个小时,真得困了 } //cout<<"result_is "<<result<<endl; return result; } int main(void) { int n,s,e,w,i,j,ans; while(scanf("%d%d",&n,&nodeNum),n)//边,结点数 { for(i=1;i<=nodeNum;i++) for(j=1;j<=nodeNum;j++) { map[i][j]=Infinity; } for(i=1;i<=n;i++) { scanf("%d%d%d",&s,&e,&w); if(map[s][e]>w)//注意这里可能有重边 map[s][e]=map[e][s]=w; } ans=prim(); if(ans==-1) cout<<"?"<<endl; else cout<<ans<<endl; } return 0; } |