普里姆算法(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;
}