普里姆算法(Prim)
普里姆算法基本思想:从图中某个顶点V0开始,将V0到其他顶点的所有边当做候选边,重复以下步骤n-1次,使得其他n-1个顶点并入到树中:1、从候选边中挑选出权值最小的边输出,并将该边另一端相接的顶点V并入树中;2、考察所有剩余顶点Vi,如果(V,Vi)的权值比lowcost[Vi]小则用(V,Vi)的权值更新lowcost[Vi]。
普里姆算法模板
#define MAXN 101 //定义顶点的最大可达数 int n, sum; //顶点数,权值和 int map[MAXN][MAXN]; //以邻接矩阵存储权值 void prim() { int vset[MAXN]; //记录顶点是否访问过 int lowcost[MAXN]; //最小权值记录 int i, j; for ( i=0; i<n; i++) { vset[i] = 0; lowcost[i] = map[0][i]; } vset[0] = 1; int u, min; for ( i=1; i<n; i++) { min = 100001; for ( j=1; j<n; j++) //从备选边中选出最小边 { if ( ! vset[j] && lowcost[j] < min && lowcost[j] > 0) { u = j; min = lowcost[j]; } } vset[u] = 1; sum += min; for ( j=1; j<n; j++) //更新备选边 { if (! vset[j] && map[u][j] < lowcost[j] ) lowcost[j] = map[u][j]; } } }
克鲁斯卡尔算法(Kruskal)
克鲁斯卡尔算法基本思想:将图中边按照从小到大排序,然后从最小边开始扫描,并检测当前边是否是为候选边,即是否该边的并入会构成回路(使用并查集),如果不构成回路,则将该边并入当前生成树中,直到所有边都检测为止。
克鲁斯卡尔算法模板
#include <stdio.h> #include <queue> using namespace std; const int Maxv =101; typedef struct { int from,to,cost; }Node; bool operator > (Node a,Node b) { if( a.cost > b.cost ) return true; return false; } int dis[Maxv][Maxv]; //dis以邻接矩阵形式表示一幅图 dis[i][j]为0时表示i点和j点不连通 int v[Maxv]; //并查集 int getRoot(int a) { while(a!=v[a]) a=v[a]; return a; } int main() { int sum; priority_queue< Node,vector<Node>,greater<Node> > Q; //返回最小数 int vn,i,j; while( scanf( "%d" , &vn ) != EOF ) { //输入图部分 for( i = 1 ; i <= vn ; i++ ) for( j = 1 ; j <= vn ; j++ ) scanf( "%d" , &dis[i][j] ); for( i = 1 ; i <= vn ; i++ ) v[i] = i; while( !Q.empty() ) Q.pop(); //把每条边压入堆中 for( i = 1 ; i < vn ; i++ ) for( j = i+1 ; j <= vn ; j++ ) if( dis[i][j] ) { Node e; e.from = i , e.to= j , e.cost = dis[i][j]; Q.push(e); } sum = 0; while( Q.size() != 0 ) { Node e; e = Q.top(); Q.pop(); if( getRoot(e.from) != getRoot(e.to) ) { sum += e.cost; v[getRoot(e.from)] = getRoot(e.to); } } printf( "%d\n" , sum ); //所需的最小值 } return 0; }