prim 加点
求最小生成树的一种贪心算法
把有权连通图中的所有点,分入两个集合A,B
A是已被记入最小生成树中的点,B是没有被记入的
每一次操作,在A中找到 i,在B中找到 j,使以i 与 j为端点的边的权值最小
开始时定义一点为源头,从这个源头逐渐蔓延
过程 从任意一个点开始,直至所有点相连
时间 复杂度 O(n^2)
void prim() {
tot=0,vis[s]=1;
for(ri i=1; i<=n; ++i) dis[i]=f[s][i];
for(ri i=1; i<=n; ++i) {
minn=maxx,k=0;
for(ri j=1; j<=n; ++j) {
if(!vis[j]&&dis[j]<minn) minn=dis[j],k=j;
tot+=minn,vis[k]=1;
for(ri j=1; j<=n; ++j) if(dis[j]>f[k][j]) dis[j]=f[k][j]; } } }
kruskal 加边
求最小生成树的一种贪心算法
主线是按从小到大的排序来选择边
暗线是一个必要条件:要成树
也就是,原来的树加上这次操作的边不成环,且使 n-1 条边连接 n 个点,不漏点
过程 从最小边开始,直至已操作 n-1 条
时间 复杂度O(ElogE)
void kruskal() {
for(ri i=1; i<=n; ++i) fa[i]=i;//按点循环
sort(a+1,a+1+n,cmp);
for(ri i=1; i<=m; ++i) {//按边循环
if(k==n-1) break;//n个点,用n-1条边相连
int r1=find(a[i].x),r2=find(a[i].y);
if(r1!=r2) fa[r2]=r1,++k,tot+=a[i].w; } }//长边接短边
prim 和 kruskal
类似于 练习时一道一道写 ( prim ) 和挑着写 ( kruskal )
挑着写灵巧方便省力,但遇到练习过多时,挑不过来,就不适用
一道一道写就显得严丝合缝一些
同理
kruskal 简单易操作,但搞不定节点过多的题
prim 则格外适用于数据量大、连通图边数多的问题
另外 prim也便于解决近点输出的问题
over