【无码专区1】简单路径的第二大边权(启发式合并+最小生成树)

这篇具有很好参考价值的文章主要介绍了【无码专区1】简单路径的第二大边权(启发式合并+最小生成树)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

只有std,没有自我实现,所以叫做无码专区

description

给一张无向图,多次询问,每次询问两个点之间所有简单路径(不重复经过点)中边权第二大(不是严格第二大)的权值的最小值。

数据范围: 1 0 5 10^5 105 级别

我的想法

50 % 50\% 50% 的数据 q , n ≤ 1 0 3 , m ≤ 2 × 1 0 3 : q,n\le 10^3,m\le 2\times 10^3: q,n103,m2×103:

先做一次最小生成树,求出任意两点之间联通的最小边权(某条路径的最大边权值)。

每次询问 ( u , v ) (u,v) (u,v) ,我直接枚举中间转折点 i i i,强制这条路径是 u → i → v u\rightarrow i\rightarrow v uiv。【 → \rightarrow 代指一条路径】

第二大边权就是 ( u , i ) (u,i) (u,i) 联通路径的最大值和 ( v , i ) (v,i) (v,i) 联通路径的最大值,二者中的较小值。

旁边的 Oxide \text{Oxide} Oxide 巨佬认为很有可能 u → i u\rightarrow i ui i → w i\rightarrow w iw 之间经过了同样的点。

i.e. u → x → i → x → v u\rightarrow x\rightarrow i \rightarrow x\rightarrow v uxixv

但后面再仔细一想,就算这是的答案会被 i i i 更新,但是后面一定会枚举到 x x x,显然 u → x → v u\rightarrow x\rightarrow v uxv 会比以前的路径少了 ( x , i ) (x,i) (x,i) 一段。

路径上的边权最大值一定是不减的

所以多的 ( x , i ) (x,i) (x,i) 一段只可能使最大边权增大 / 不变。

那么 x x x 的决策一定是不劣于 i i i 的决策的。

另有 20 % 20\% 20% 是树:两个点之间只有一条简单路径,可以直接倍增求路径的第二大边权值。

综上,本题自我实现分值应该在 7 0 ′ 70' 70

solution

类似最小生成树的方法,从小到大加边。

如果加完一条边后, u , v u,v u,v 之间只差一条边联通,那么显然这条边就是第二小,也就是最终的答案。

考虑怎么维护?

N ( u ) : N(u): N(u): u u u 有直接边相连,但还没有相连的点的集合【当前枚举边的权值暂时小于等于这些点与 u u u 的权值,最小生成树的写法就还没有加入这些边】

或者理解为:还差一条边就能联通的点的集合

考虑启发式合并,每次合并 u , v u,v u,v 各自所在的连通块。

此时可能出现: N ( u ) N(u) N(u) 中的点 x x x v v v 相连【在 v v v 连通块里面】 ,或, N ( v ) N(v) N(v) 中的点 y y y u u u 相连【在 u u u 连通块里面】

这个时候意味着,加上 u − v u-v uv 这条边后,还差 u − x u-x ux v − y v-y vy 这一条边就会使得 u , v u,v u,v 相连,所以 u − v u-v uv 这条边权就是最后的答案。

如果直接枚举 N ( u ) , N ( v ) N(u),N(v) N(u),N(v) 则不符合时间限制。

我们可以这么做:

  • 遍历 N ( u ) N(u) N(u) 的所有点,然后看是否在 v v v 的询问中。

    i.e. 假设 x ∈ N ( u ) , x ∈ q ( v ) x\in N(u),x\in q(v) xN(u),xq(v) x − u x-u xu 之间的边还没有加入。

    此时加入为 u − v u-v uv 的边。一旦加入完, x → u → v x\rightarrow u\rightarrow v xuv就只差 x − u x-u xu 的一条边。

    所以答案就是现在操作的 u − v u-v uv 边的边权。

    这样就处理了挂在 v v v 上面的某些 通过 u u u 连通块中某些点和边解决 的询问。

  • 遍历 u u u 里面的所有询问,判断是否在 N ( v ) N(v) N(v) 中。

    i.e. 假设 x ∈ q ( u ) x\in q(u) xq(u) x − v x-v xv 之间的边还没有加入。

    此时加入为 u − v u-v uv 的边。一旦加入完, x → v → u x\rightarrow v\rightarrow u xvu 就只差 x − v x-v xv 的一条边。

    所以答案是 u − v u-v uv 现在这条边的边权。

    这样就处理了挂在 u u u 上面的某些 通过 v v v 连通块中某些点和边解决 的询问。

这么做会发现,虽然是合并两个联通块和处理两个联通块各自挂着的询问,但是枚举的只有一个联通块的信息。

所以启发式合并,就用 N ( u ) + q ( u ) N(u)+q(u) N(u)+q(u) N ( v ) + q ( v ) N(v)+q(v) N(v)+q(v) 大小比较,选较小的进行枚举。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

合并具体而言:枚举其中一个较小连通块的信息,进行答案处理。所有挂在 u , v u,v u,v 点的询问和边都重新挂在合并后新连通块的根 w w w 上。

i.e. 询问 u , x u,x u,x 的答案,合并后相当于问 w , x w,x w,x 的答案,因为反正 u − w u-w uw 的边权不是第二大。原本 u − x u-x ux 的一条边,变成 w − x w-x wx 的一条边。

所以上面的形如 x − u x-u xu :不一定表示原先加入的 m m m 条边就是 x − u x-u xu,而是可能通过 x − a − b − c − . . . − u x-a-b-c-...-u xabc...u ,不断合并,可能代指的是一条简单路径。

参考code文章来源地址https://www.toymoban.com/news/detail-475058.html

#include <bits/stdc++.h>
using namespace std;

#define N 400005

#define pb push_back
int fa[N];
struct node {
	int x, y, z;
} b[N];
int ans[N], n, m, Q;
set<array<int, 2>> q[N];
set<int> e[N];

int get(int x) {
	if (fa[x] == x)
		return x;
	return fa[x] = get(fa[x]);
}

inline bool cmp(node x, node y) {
	return x.z < y.z;
}

void combine(int x, int y, int val) {
	for (auto u : e[x]) {
		while (1) {
			auto it = q[y].lower_bound({u, -1});
			if (it == q[y].end() || (*it)[0] != u)
				break;
			int id = (*it)[1];
			ans[id] = val;
			assert(q[y].count({u, id}));
			assert(q[u].count({y, id}));
			q[y].erase(it);
			q[u].erase({y, id});
		}
	}
	vector<array<int, 2>> delq;
	for (auto u : q[x]) {
		if (e[y].count(u[0])) {
			ans[u[1]] = val;
			q[u[0]].erase({x, u[1]});
			delq.pb(u);
		}
	}
	for (auto u : delq)
		q[x].erase(u);
	fa[x] = y;
	for (auto v : e[x]) {
		assert(e[v].count(x));
		e[v].erase(x);
		if (v != y) {
			e[v].insert(y);
			e[y].insert(v);
		}
	}
	e[x].clear();
	for (auto v : q[x]) {
		assert(v[0] != y);
		assert(q[v[0]].count({x, v[1]}));
		q[v[0]].erase({x, v[1]});
		q[v[0]].insert({y, v[1]});
		q[y].insert({v[0], v[1]});
	}
	q[x].clear();
}

int main() {
	freopen("path.in", "r", stdin);
	freopen("path.out", "w", stdout);
	scanf("%d%d%d", &n, &m, &Q);
	for (int i = 1; i <= n; i++)
		e[i].clear(), q[i].clear();
	for (int i = 1; i <= m; i++) {
		scanf("%d%d%d", &b[i].x, &b[i].y, &b[i].z);
		e[b[i].x].insert(b[i].y);
		e[b[i].y].insert(b[i].x);
	}
	for (int i = 1; i <= n; i++)
		fa[i] = i;
	sort(b + 1, b + 1 + m, cmp);
	for (int i = 1; i <= Q; i++) {
		ans[i] = 0;
		int x, y;
		scanf("%d%d", &x, &y);
		if (e[x].count(y)) {
			ans[i] = 1;
			continue;
		}
		q[x].insert({y, i});
		q[y].insert({x, i});
	}
	for (int i = 1; i <= m; i++) {
		b[i].x = get(b[i].x), b[i].y = get(b[i].y);
		if (b[i].x == b[i].y)
			continue;
		if (q[b[i].x].size() + e[b[i].x].size() > q[b[i].y].size() + e[b[i].y].size())
			swap(b[i].x, b[i].y);
		combine(b[i].x, b[i].y, b[i].z + 1);
	}
	for (int i = 1; i <= Q; i++)
		printf("%d\n", ans[i] - 1);
}

到了这里,关于【无码专区1】简单路径的第二大边权(启发式合并+最小生成树)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 启发式搜索 :A*算法详解

    A*算法,(A-Star)算法是一种静态路网中求解 最短路径 最有效的 直接搜索方法 ,也是解决许多搜索问题的有效算法。 算法中的距离估算值与实际值 越接近 ,最终搜索速度越快。 对于求两个点之间的最短路 普通的BFS是按层遍历的过程,以起点为中心,以到终点的最短路为半径

    2023年04月08日
    浏览(42)
  • 人工大猩猩部队优化器:一种新的面向全局优化问题的自然启发元启发式算法(Matlab代码实现)

           目录 💥1 概述 📚2 运行结果 🎉3 参考文献 👨‍💻4 Matlab代码 元启发式在解决优化问题方面发挥着关键作用,其中大多数都受到自然界中自然生物集体智慧的启发。本文提出了一种新的元启发式算法,其灵感来自自然界大猩猩部队的社会智能,称为人工大猩猩部

    2024年02月01日
    浏览(43)
  • 树上启发式合并(dsu on tree)

    dsu on tree dsu text{dsu} dsu 一般指 disjoint set union text{disjoint set union} disjoint set union ,即并查集。 dsu on tree text{dsu on tree} dsu on tree 指树上合并与查询操作,但它的实现和普通的并查集并无关联,两者的共同点仅仅在于都能合并集合和查询而已。 dsu on tree text{dsu on tree} d

    2024年02月16日
    浏览(41)
  • 【启发式算法】灰狼优化算法【附python实现代码】

    写在前面: 首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 路虽远,行则将至;事虽难,做则必成。只要有愚公移山的志气、滴水穿石的毅力,脚踏实地,埋头苦干,积跬

    2024年02月16日
    浏览(35)
  • 非梯度类启发式搜索算法:Nelder Mead

    Hello,今天给大家介绍一种不基于梯度的优化算法 Nelder Mead。 Nelder Mead 算法通常是用来求解非线性(nonlinear)、导函数未知情况下目标函数的最大值或者最小值。学过梯度下降的同学应该知道,梯度下降类算法的每一步都需要计算当前位置的梯度,从而更新当前解使得最终逐

    2024年02月02日
    浏览(45)
  • 元启发式算法库 MEALPY 初体验-遗传算法为例

    官网: MealPY官网 开源许可: (GPL) V3 MEALPY (MEta-heuristic ALgorithms in PYthon) 是一个提供最新自然启发式元启发算法的Python模块,它是最大的此类Python模块之一。这些算法模仿自然界中的成功过程,包括生物系统以及物理和化学过程。mealPy 的目标是免费向所有人分享元启发领域的知识

    2024年04月11日
    浏览(42)
  • 求解三维装箱问题的启发式深度优先搜索算法(python)

    给定一个容器(其体积为 V V V ) 和一系列待装载的箱子,容器和箱子的形状都是长方体。问题的目标是要确定一个可行的箱子放置方案使得在满足给定装载约束的情况下,容器中包含的箱子总体积 S S S 尽可能的大,即填充率尽可能的大,这里填充率指的是 S / V ∗ 100 % S/ V * 1

    2024年02月05日
    浏览(99)
  • 【论文阅读】聚集多个启发式信号作为监督用于无监督作文自动评分

    本文提出一个新的无监督的AES方法ULRA,它不需要真实的作文分数标签进行训练; ULRA的核心思想是使用多个启发式的质量信号作为伪标准答案,然后通过学习这些质量信号的聚合来训练神经自动评分模型。 为了将这些不一致的质量信号聚合为一个统一的监督信号,我们将自动

    2024年02月16日
    浏览(39)
  • 如何进行测试分析与设计-HTSM启发式测试策略模型 | 京东云技术团队

    测试,没有分析与设计就失去了灵魂; 测试人员在编写用例之前,该如何进行测试分析与设计呢?上次在《测试的底层逻辑》中讲到了【输入输出测试模型】,还讲到了【2W+1H测试分析法】,但2W1H分析法是初步的分析方法,具体在测试中如何落地,还需要更细的设计。 今天

    2024年02月05日
    浏览(49)
  • 启发式搜索算法:A算法(全局、局部择优算法)+A*算法 解决八数码问题

    参考博客:人工智能搜索策略:A*算法 在图搜索算法中,如果能在搜索的每一步都利用估价函数f(n)=g(n)+h(n)对Open表中的节点进行排序,则该搜索算法为 A算法 。由于估价函数中带有问题自身的启发性信息,因此,A算法又称为启发式搜索算法。 对启发式搜索算法,又可根据搜

    2024年02月10日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包