【一本通1489:构造完全图】题解
题目链接
题目
对于完全图 ,若有且仅有一棵最小生成树为 ,则称完全图 是树 扩展出的。
给你一棵树 ,找出 能扩展出的边权和最小的完全图 。
思路
要使一个图总存在唯一最小生成树,需满足所有非最小生成树的边(假设连接 ),使这条边的边权 大于 在最小生成树上的最短路径的最大边权。
因此,我们可以先dfs一遍求出每个点到根节点的最大值,然后完全图上每条边暴力匹配,复杂度是 的。
考虑利用类似kruskal的思想,先对最小生成树上的边从小到大排序,然后按排序后的顺序进行操作。
此时对于当前这条边来说,假设其连接 ,且其边权为 ,如下图所示:
图中橙色边代表新加入的边, 分别代表与 直接或间接相连的节点群,我们可以用并查集把它们并到一个集合里面。
在并查集的过程中,我们记录 代表 所在集合的大小,必须满足 是这个集合的祖先。
设 的祖先为 , 的祖先为 。
而我们现在要还原成完全图 ,则我们在两个集合中任意点都应加边,所以总加边数为 。
而由于我们已经排了序,所以 必然是当前树上最大边权,则 条边的边权应为 。
此时对于树上这条边对答案的贡献为 。
时间复杂度
Code
// Problem: 1489:构造完全图
// Contest: SSOIER
// URL: http://ybt.ssoier.cn:8088/problem_show.php?pid=1489
// Memory Limit: 65 MB
// Time Limit: 1000 ms
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 100010
//#define M
//#define mo
struct node
{
int u, v, w;
}a[N];
int n, m, i, j, k, T;
int f[N], g[N], ans, x, y;
int fa(int x)
{
if(f[x]==x) return x;
return f[x]=fa(f[x]);
}
bool cmp(node x, node y)
{
return x.w<y.w;
}
signed main()
{
// freopen("tiaoshi.in","r",stdin);
// freopen("tiaoshi.out","w",stdout);
n=read();
for(i=1; i<=n; ++i) f[i]=i, g[i]=1;
for(i=1; i<n; ++i)
{
a[i].u=read();
a[i].v=read();
a[i].w=read();
ans+=a[i].w;
}
sort(a+1, a+n, cmp);
for(i=1; i<n; ++i)
{
x=fa(a[i].u);
y=fa(a[i].v);
ans+=(a[i].w+1)*(g[x]*g[y]-1);
f[x]=y; g[y]+=g[x];
}
printf("%lld", ans);
return 0;
}
总结
这是一道很好的思维题。
关键在于要思考出一个性质:如果只存在唯一最小生成树,则所有非树上的边的边权一定要大于所连接的两点点在树上路劲上的最大值。
然后推出暴力做法,为了优化,可以从Kruskal的思想去考虑,排序后套个乘法原理即可。
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/16285749.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战