From 8403038f4dd8a51983d57ffa714ee0aed8ce9ead Mon Sep 17 00:00:00 2001
From: ember <1279347317@qq.com>
Date: Sun, 27 Jul 2025 12:34:39 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=87=E7=AB=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
content/page/about/index.md | 2 +-
content/post/算法题/nju01.md | 266 +++++++++++++++++++++++++++++++++++
2 files changed, 267 insertions(+), 1 deletion(-)
create mode 100644 content/post/算法题/nju01.md
diff --git a/content/page/about/index.md b/content/page/about/index.md
index 78110b2..209d4a0 100644
--- a/content/page/about/index.md
+++ b/content/page/about/index.md
@@ -35,7 +35,7 @@ links:
---
-🎓 NEU 软院大三在读,目前🐧厂实习ing
+🎓 NEU 软院大三在读,曾经的🐧厂实习er
🎹 会钢琴、喜欢音乐和唱歌
💻 Node.js、Java、Python、C++、Go、Vue 什么的都会一点
🔧 技术迷,喜欢折腾
diff --git a/content/post/算法题/nju01.md b/content/post/算法题/nju01.md
new file mode 100644
index 0000000..e647c6c
--- /dev/null
+++ b/content/post/算法题/nju01.md
@@ -0,0 +1,266 @@
+---
+title: 南软/智软2025年开放日机试第1题
+description: 图论+并查集问题
+date: 2025-07-27T11:59:00+08:00
+slug: nju01
+# image: helena-hertz-wWZzXlDpMog-unsplash.jpg
+categories:
+ - 算法题
+tags: [
+ "图论",
+ "并查集",
+ "算法",
+ "夏令营"
+]
+math: true
+---
+
+# 题目
+
+有一个圆上均匀分布着L个点(编号按逆时针顺序依次为1~L)。在这些点中还存在m条弦。如果在圆弧上从一个点走到另一个相邻的点,需要支付1元的费用;但如果通过弦来走(包括交点),则无需支付费用。
+例如,如图所示,如果存在弦(1,3)和(2,4),则从点1到点2可以先从1走到两条弦的交点,再从交点走到2,这样就无需收费。请你设计算法,找出某两个点之间最少的交通费。
+
+- 程序的第一行输入三个整数:L、m、q,用空格分隔。
+- 接下来输入m行,每行两个整数,表示一条弦。
+- 接下来输入q行,每行两个整数,表示q个问题。如“1 2”则表示一个问题,表示点1和2之间的最少交通费。
+- 程序的输出为q行,每行为一个问题的答案。
+
+
+
+## 示例输入
+```
+5 2 1
+1 3
+2 4
+1 2
+```
+
+## 示例输出
+```
+0
+```
+
+# 机试情况
+
+南软/智软的夏令营机试是4小时4道题,每题100分,满分400分。4小时内排行榜上此题无人AC,不过有人拿到60-70分。我自己在考场也是没完全做出来,事后思考后才成功做出。
+
+# 解题思路
+
+我们可以自然地把这个问题抽象为一个图,其中包含两种不同代价的边:
+
+- 圆弧边:连接圆上相邻的两个点,例如点 i 和点 i+1(以及点 L 和点 1)。走这些边需要花费1元,因此它们的边权为 1。
+- 免费边:所有通过弦和弦的交点构成的路径。走这些边无需花费,因此它们的边权为 0。
+
+问题的关键在于,所有通过弦和交点能够互相到达的点,实际上构成了一个“免费交通网络”。网络内的任意两点之间都可以零费用到达。我们可以把这样一个网络视为一个连通分量。
+
+所以我们可以用**并查集** 来高效地处理和合并这些连通分量。
+
+1. **初始化**:将圆上的 `L` 个点每一个都看作一个独立的集合。
+2. **合并弦端点**:对于给定的 `m` 条弦,每条弦 `(u, v)` 都意味着 `u` 和 `v` 是零费用连通的。我们将 `u` 和 `v` 所在的集合合并。
+3. **合并相交弦**:接下来,我们需要找出所有相交的弦。
+ - **如何判断两条弦是否相交?** 假设有两条弦 `(a, b)` 和 `(c, d)`。为了方便判断,我们先将每条弦的端点按编号从小到大排序,即 `u1 = min(a, b), v1 = max(a, b)` 和 `u2 = min(c, d), v2 = max(c, d)`。 这两条弦在圆内相交的充要条件是,它们的端点在圆上是交错排列的。也就是说,必须满足 `u1 < u2 < v1 < v2` 或者 `u2 < u1 < v2 < v1`。
+ - 对于每一对相交的弦,例如 `(a, b)` 和 `(c, d)`,它们的所有四个端点 `a, b, c, d` 都应该在同一个零费用连通分量中。我们只需将其中任意一个点(如 `a`)与另一条弦的任意一个点(如 `c`)所在的集合合并即可。
+
+完成以上步骤后,并查集就完整地记录了所有的零费用连通分量。
+
+**第二步:计算两个点之间的最短交通费**
+
+对于每一个查询 `(s, t)`:
+
+1. 首先,我们使用并查集的 `find` 操作检查 `s` 和 `t` 是否在同一个连通分量中。
+ - 如果 `find(s) == find(t)`,说明它们在同一个免费交通网络内,可以直接到达,费用为 0。
+2. 如果它们不在同一个连通分量中,费用就来自于在圆弧上从一个连通分量“跳”到另一个连通分量的次数。这可以转化为一个在**“分量图”**上的最短路问题。
+ - **构建分量图**:图中的每个节点代表一个连通分量。
+ - **分量图的边**:如果圆弧上相邻的两个点 `i` 和 `i+1` 属于不同的连通分量(即 `find(i) != find(i+1)`),我们就在这两个分量对应的节点之间连一条边,权重为 1。
+ - **求解**:问题就变成了,在分量图上,从 `s` 所在的分量走到 `t` 所在的分量,最少需要经过几条边。这是一个典型的无权图最短路问题,可以使用**广度优先搜索 (BFS)** 来解决。
+
+# C++ 代码
+
+```cpp
+#include
+#include
+#include // std::iota
+#include // std::swap, std::min, std::max
+#include // std::pair
+#include