对于n个节点的连通图,找到n-1条权值最小且无回路的边使所有节点连通。
Prim算法
将所有节点分为2个集合,一个是已生成树的集合U,和剩余的集合V-U
:第i个节点到U集合的直接连边的最近的点
:第i个节点到U集合的直接连接的边的最小权值
无直接连边的点无穷大,已经在集合中的点
void prim()
{
memset(lowCost,inf,sizeof(lowCost));
memset(closest,inf,sizeof(closest));
for(int i=head[1];i;i=nxt[i])
{
int y=to[i];
closest[y]=1;
lowCost[y]=min(lowCost[y],edge[i]);//有重边时要取最小的
}
lowCost[1]=closest[1]=0;
for(int i=1;i<n;i++)
{
int minCost=inf,u=0;
for(int j=1;j<=n;j++)
if(lowCost[j] && lowCost[j]<minCost)
{
minCost=lowCost[j];
u=j;
}
if(!u)
{
printf("orz\n");
return;
}
lowCost[u]=0;
ans+=minCost;
for(int j=head[u];j;j=nxt[j])
{
int y=to[j];
if(edge[j]<lowCost[y])
lowCost[y]=edge[j],closest[y]=u;
}
}
printf("%d\n",ans);
}
Kruskal算法
对边按权值从小到大排序,边的两点在不同集合则选取,在同一集合则跳过。采用并查集判断集合关系。