LOJ10067构造完全图【克鲁斯卡尔】
题目描述
对于完全图 ,若有且仅有一棵最小生成树为 ,则称完全图 是树 扩展出的。
给你一棵树 ,找出 能扩展出的边权和最小的完全图 。
输入格式
第一行 表示树 的点数;
接下来 行三个整数 ;描述一条边 权值为 ;
保证输入数据构成一棵树。
输出格式
输出仅一个数,表示最小的完全图 的边权和。
样例
样例输入
4
1 2 1
1 3 1
1 4 2
样例输出
12
样例说明
添加 即可。
数据范围与提示
对于 的数据,;
对于 的数据,;
对于 的数据,。
看到题目范围,可以排除掉prim。那么就是克鲁斯卡尔了。我们考虑克鲁斯卡尔的思想,每次选择最小的一条边。因为是一颗唯一的最小生成树,所以我们就要保证在完全图上执行克鲁斯卡尔的时候每一次都会选择这条边,那么就相当于这两个集合的所有不是最小生成树上的边都必须比这条边大1才能保证唯一性和最小性
如有不理解,可看下图。中途画错了。。稍微修改一下样例
我们在{1},{2}这两个不同的并查集中,找到了一条边(1,2,1)。之所以能找到这条边,是因为这两个集合剩余边都比这条边大(这里无剩余边),连接并合并,答案+1
同上,我们又选到了(1,4,1),连接并合并,答案+1
现在来想一下,为什么选了(1,4,1)而不是(2,4)这条边?是因为(2,4)这条边比(1,4,1)要大1,即(2,4,2)才能保证生成树的唯一性
现在我们又选到了(1,3,2)
同上,之所以不选(4,3)或(2,3)是因为这两条边更大,为了满足最小性,这两条边的长度为3
至此,跑完克鲁斯卡尔,正确性显然
代码就很好写了,稍微修改一下并查集记录一下节点个数,用乘法原理即OK
#include<bits/stdc++.h>
using namespace std;
int n;
int father[100010];
long long cnt[100010];
struct Node
{
int a,b;long long dis;
}Edge[100010];
bool cmp(Node a,Node b)
{
return a.dis<b.dis;
}
int getfather(int x)
{
return father[x]==x?x:father[x]=getfather(father[x]);
}
long long ans;
int main()
{
int s,t;long long d;
scanf("%d",&n);
for(int i=1;i<=n;i++)
father[i]=i,cnt[i]=1;
for(int i=1;i<n;i++)
{
scanf("%d%d%lld",&s,&t,&d);
Edge[i].a=s,Edge[i].b=t,Edge[i].dis=d;
ans+=d;
}
sort(Edge+1,Edge+n,cmp);
for(int i=1;i<n;i++)
{
int fx=getfather(Edge[i].a),fy=getfather(Edge[i].b);
ans+=(cnt[fx]*cnt[fy]-1)*(Edge[i].dis+1);//这是化简后的结果
father[fy]=fx;
cnt[fx]+=cnt[fy];
}
printf("%lld",ans);
return 0;
}
谢谢
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构