boruvka
boruvka
是一种对于完全图求最小生成树很好用的算法。
算法流程
每轮为当前每个连通块找到与其最近的连通块,并连边,直到只有一个连通块。
正确性
最后的最小生成树上的每个点,显然都会保留它连出的最短的边。
否则断掉现在它连出的一条边,再连最短的边一定更优。
那么每轮过后,把一个连通块缩成一个点,按照上面的结论一直做下去就是对的。
轮数
每次连通块个数至少除以二,因为最坏情况下的连边就是1-2,3-4,5-6,...
所以最多有
例题
Atcoder_cf17_final_j Tree MST
做法挺巧妙的。
我们先算出每个点和不同连通块的点的最短边长,以及最近点在哪个块,然后合并到这个点的连通块上去。
设
考虑树形
但是!这个点可能是在同一块里的,怎么办呢?
我们可以不只维护最近的点,另外再维护一个和当前最近点不是同一块的次近点。
这样的话,如果最近点在同一块里,次近点就是答案了。
第二遍
代码:
#include<bits/stdc++.h>
#define int long long
#define mkp make_pair
#define fi first
#define se second
using namespace std;
const int N=2e5+10;
int n,cnt,res,a[N],f[N],s[N];
int idx,hd[N],to[N<<1],nxt[N<<1],len[N<<1];
pair<int,int>p,s1[N],s2[N],ans[N];
int find(int x)
{
if(f[x]==x)return x;
return f[x]=find(f[x]);
}
void add(int u,int v,int w)
{
++idx,to[idx]=v,nxt[idx]=hd[u],len[idx]=w,hd[u]=idx;
return;
}
pair<int,int>cmx(pair<int,int>a,pair<int,int>b,pair<int,int>c,int f)
{
p=mkp(1e18,-1);
if(a.se!=f)p=min(p,a);
if(b.se!=f)p=min(p,b);
if(c.se!=f)p=min(p,c);
return p;
}
void dfs1(int u,int fa)
{
s1[u]=mkp(s[u]+a[u],f[u]);
s2[u]=mkp(1e18,-1);
for(int i=hd[u];i;i=nxt[i])
{
int v=to[i];
if(v==fa)continue;
s[v]=s[u]+len[i];
dfs1(v,u);
if(s1[u]>s1[v])s2[u]=cmx(s1[u],s2[u],s2[v],s1[v].se),s1[u]=s1[v];
else s2[u]=cmx(s2[u],s1[v],s2[v],s1[u].se);
}
return;
}
void dfs2(int u,int fa)
{
s1[u].fi-=2*s[u],s2[u].fi-=2*s[u];
if(fa)if(s1[u]>s1[fa])s2[u]=cmx(s2[fa],s1[u],s2[u],s1[fa].se),s1[u]=s1[fa];
else s2[u]=cmx(s2[u],s1[fa],s2[fa],s1[u].se);
if(s1[u].se!=f[u])ans[f[u]]=min(ans[f[u]],mkp(s1[u].fi+s[u]+a[u],s1[u].se));
else if(s2[u].se!=f[u])ans[f[u]]=min(ans[f[u]],mkp(s2[u].fi+s[u]+a[u],s2[u].se));
for(int i=hd[u];i;i=nxt[i])
{
int v=to[i];
if(v==fa)continue;
dfs2(v,u);
}
return;
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1,u,v,w;i<n;i++)scanf("%lld%lld%lld",&u,&v,&w),add(u,v,w),add(v,u,w);
for(int i=1;i<=n;i++)f[i]=i;
cnt=n;
while(cnt>1)
{
dfs1(1,0);
for(int i=1;i<=n;i++)ans[i]=mkp(1e18,-1);
dfs2(1,0);
for(int i=1;i<=n;i++)
{
if(f[i]==i&&ans[i].se>0&&find(i)!=find(ans[i].se))f[i]=ans[i].se,res+=ans[i].fi;
}
cnt=0;
for(int i=1;i<=n;i++)cnt+=(find(i)==i);
}
printf("%lld",res);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App