教堂(church)
这本质是一个贪心题目, 没有下面说的那么复杂,你自己多画几个图,就可以发现不得不走 斜边的情况: 奇数个点
这是一道经典的**网格图哈密顿回路(Grid Graph Hamiltonian Cycle)**问题的变种,结合了最短路径的计算。以下是对该题目的详细解析。
1. 题目分析
核心目标:
在一个
移动规则与距离: 每个点与周围 8 个方向相连(上、下、左、右、左上、右上、左下、右下)。
- 水平或垂直移动(正方向):距离为
。 - 对角线移动(斜方向):根据勾股定理,距离为
。
为了使总路程最短,我们应该尽可能多地使用距离为
2. 解题思路
我们可以根据网格中点的总数
将网格看作国际象棋棋盘,相邻的(水平/垂直)格子颜色不同(黑白相间)。
- 水平/垂直移动:总是从黑格走到白格,或从白格走到黑格(改变颜色)。
- 对角线移动:总是从黑格走到黑格,或从白格走到白格(保持颜色不变)。
情况一: 为偶数
如果网格点的总数是偶数,说明黑格和白格的数量相等。
在二分图(网格图仅考虑正方向边时是二分图)中,如果节点数为偶数,通常存在一条哈密顿回路,只包含水平和垂直边。
我们可以采用“蛇形走位”的方式遍历全图:
例如
- 边的数量:遍历
个点回到起点,需要走 步。 - 最短距离:
。 - 样例验证:输入
2 3,总数 6,输出6.00。符合公式。
情况二: 为奇数
如果网格点的总数是奇数(意味着
- 第 1 步:黑
白 - 第 2 步:白
黑 - …
- 第
步(回到起点):因为 是奇数,第 步应该走到白色格子。 但我们的起点是黑色的。这意味着,仅凭奇数步的“变色移动”,无法回到同色的起点。
解决方案: 为了解决这个奇偶性冲突,我们需要在路径中加入一步对角线移动(斜向)。
-
对角线移动不改变颜色(黑
黑),这相当于消耗了一步移动次数,但没有改变颜色的极性,从而修正了奇偶性,使得最后能回到起点。 -
为了距离最短,我们只需要1 步斜向移动,其余
步全部用正向移动。 -
最短距离:
。
特殊情况: 或 (单行或单列)
虽然题目给出的范围较大且通常这类题目隐含
- 路径:
。 - 距离:
去程 + 回程 = 。 (注:绝大多数此类题目测试数据集中在 的情况,但写代码时最好特判)
3. 算法总结
- 计算点总数
。 - 特判:如果
或 : - 如果
,距离为 0。 - 否则距离为
。
- 如果
- 一般情况 (
): - 如果
是偶数:答案是 (即 double(m * n))。 - 如果
是奇数:答案是 。
- 如果
4. C++ 代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm> // for max
using namespace std;
int main() {
long long m, n; // 使用 long long 防止乘积溢出(虽然题目10000内int够用,但好习惯)
if (cin >> m >> n) {
// 特判线性情况 (m=1 或 n=1)
if (m == 1 || n == 1) {
if (m == 1 && n == 1) {
printf("0.00\n");
} else {
long long len = max(m, n);
printf("%.2f\n", (double)2 * (len - 1));
}
}
// 一般矩形情况
else {
long long total = m * n;
if (total % 2 == 0) {
// 偶数个点:全走直线
printf("%.2f\n", (double)total);
} else {
// 奇数个点:走一步斜线,其余直线
// 距离 = (Total - 1) * 1 + sqrt(2)
printf("%.2f\n", (double)(total - 1) + sqrt(2));
}
}
}
return 0;
}
5. 关键点回顾
- 偶数点阵:可以通过蛇形填数形成闭环,全部由长度为 1 的边组成。
- 奇数点阵:由于二分图奇偶性限制,无法仅用长度为 1 的边形成闭环,必须借用至少一条长度为
的对角线边来“跳过”颜色的变换。