最小生成树
\[最小生成树
\begin{cases}
\ Prim算法 \quad \begin{cases}\ 朴素版Prim\ \\[3ex] 堆优化版Prim\ \end{cases}\ \\[5ex]
Kruskal算法
\end{cases}\
\]
Prim算法
朴素Prim基本思想:
dist [ i ] \(\longleftarrow\) + \(\infty\)
for (int i = 0 ; i < n ; i ++)
$\quad$ $\quad$ t \(\longleftarrow\) 找到集合外距离最近的点
$\quad$ $\quad$ 用t更新其他点到集合的距离
$\quad$ $\quad$ st [ t ] = true
//朴素版Prim算法模板
int n; //表示点数
int g[N][N]; //邻接矩阵,存储所有边
int dist[N]; //存储其他点到当前最小生成树的距离
bool st[N]; //存储每个点是否已经在生成树中
//如果图不连通则返回INF(值是0x3f3f3f3f),否则返回最小生成树的树边权重之和
int prim()
{
memset(dist,0x3f,sizeof dist);
int res=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!st[j]&&(t==-1||dist[t]>dist[j]))
t=j;
if(i&&dist[t]==INF)return INF;
if(i)res+=dist[t];
st[t]=true;
for(int j=1;j<=n;j++)dist[j]=min(dist[j],g[t][j]);
}
return res;
}
Kruskal 算法
Kruskal算法基本思想:
① 将所有边按权重从小到大排序
② 枚举每一条边 a \(\to\) b ,权重c
$\quad$ $\quad$ if a、b 不连通
$\quad$ $\quad$ $\quad$ 将这条边加入集合中
//Kruskal算法模板
int n,m; //n是点数,m是边数
int p[N]; //并查集的父节点数组
int find(int x) //并查集核心操作
{
if(p[x]!=x)p[x]=find(p[x]);
return p[x];
}
struct Edge //存储边
{
int a,b,w;
bool operator<(const Edge &W)const
{
return w<W.w;
}
}edges[M];
int kruskal()
{
sort(edges,edges+m);
for(int i=1;i<=n;i++)p[i]=i; //初始化并查集
int res=0,cnt=0;
for(int i=0;i<m;i++)
{
int a=edges[i].a,b=edges[i].b,w=edges[i].w;
a=find(a),b=find(b);
if(a!b) //如果两个连通块不连通,则将这两个连通块合并
{
p[a]=b;
res+=w;
cnt++;
}
}
if(cnt<n-1)return INF;
return res;
}