(严格)次小生成树
Solution I
先求出最小生成树
由于次小生成树
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 510, M = 10010;
const LL INF = 4e18;
struct Edge
{
int u, v, w;
bool min;
bool operator <(const Edge &t) const
{
return this->w < t.w;
}
}e[M];
int n, m;
LL minv;
int fa[N];
bool tag[M];
int get(int x)
{
if (fa[x] == x) return x;
return fa[x] = get(fa[x]);
}
void kruskal(bool flag)
{
for (int i = 1; i <= n; i ++ )
fa[i] = i;
if (flag) sort(e, e + m);
for (int i = 0; i < m; i ++ )
{
if (tag[i]) continue;
int a = get(e[i].u), b = get(e[i].v);
int w = e[i].w;
if (a != b)
{
fa[a] = b;
if (flag) e[i].min = true;
minv += w;
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ )
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
kruskal(true);
LL res = INF;
for (int i = 0; i < m; i ++ )
if (e[i].min)
{
minv = 0;
tag[i] = true;
kruskal(false);
tag[i] = false;
res = min(res, minv);
}
printf("%lld\n", res);
return 0;
}
但是实现的过程中,我们会发现这种做法不易优化,且不方便求严格次小生成树。
Solution II
首先,我们要证明一个结论:对于任何一棵生成树,如果它存在(严格)次小生成树,那么一定存在一个(严格次小生成树),与自己只有一条边不同。
首先对于次小生成树证明。
假设所有次小生成树都至少有两条边与最小生成树不同,按照边权从小到大检查每一条边,找到第一个两者不同的位置,如下图:
(方框是连通块,黑圈是点A、B,蓝边是最小生成树的边e1,橙边是次小生成树的边e2)
由于A和B一定要连通,所以次小生成树必然选择了e1之后不小于e1的边(边权已经排序),此时将e2从次小生成树中删去,将e1加入次小生成树,会发现得到的树的总权值不大于原来的总权值,并且还与最小生成树不同(至少有两条边不同)。
这样,要么假设中的次小生成树这个前提不成立,要么构造出了一个不同边数少一的次小生成树。重复这个操作直到只有一条边不同,得到的就一定是次小生成树。
证毕。
对于严格次小生成树证明。
同样是上面这个图,也是同样的操作,如e1=e2,直接替换,不同边数-1;
若不同,往后找到另外一条不同的边,将它直接替换,边数也是-1;
证毕。
貌似上述这个证法有点问题,就按照算法流程去意会一下吧,先记住做法了。
证明以后再说。
- 求出最小生成树,标记树边与非树边,同时建立出最小生成树;
- 求出最小生成树上任意两点间距离的最大值和次大值;
- 枚举每一条非树边
,如果 ,直接更新答案 ;否则与次大值比较,如果比次大值大,直接更新 。
PS:所有非树边
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构