Advent of Code 2025 day7
好的,我现在需要帮用户总结一篇文章的内容,控制在100字以内。首先,我得仔细阅读文章,理解它的主要部分。 文章分为两部分。第一部分讨论超光速粒子束在歧管中的分束次数。第二部分则探讨粒子在遇到分束器时的路径数量统计方法。 在第一部分中,S是发射点,粒子束向下移动。遇到分束器^时会分束,每次分束算一次。统计方法是检查每个^上面是否有|,如果有就计数一次。 第二部分更复杂,粒子每次遇到^可以选择左或右,导致多种路径。直接递归会导致计算量爆炸,所以作者建议用动态规划和记忆化来优化,减少重复计算。 现在我需要将这些内容浓缩到100字以内。要抓住关键点:分束次数、路径数量、动态规划和记忆化方法。 可能的结构是:先说明主题,然后分别简述两部分的内容和解决方案。 确保语言简洁明了,避免使用复杂的术语,同时涵盖所有重要信息。 </think> 这篇文章讨论了超光速粒子束在歧管中的传播问题。Part 1要求统计粒子束被分束的次数,通过遍历图表并检查每个分束器是否被离子束触发来实现。Part 2则探讨了单个粒子在遇到分束器时可能的路径数量统计方法,并提出使用动态规划和记忆化技术来优化计算效率。 2025-12-8 03:22:0 Author: taxodium.ink(查看原文) 阅读量:7 收藏

day7 的输入是:

.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............

这是一个超光速粒子歧管的图表(a diagram of the tachyon manifold), S 是发射超光速粒子束的地方。超光速粒子束总是向下移动。超光速粒子束可以自由穿过空白区域 (.)。但是,如果超光速粒子束遇到分束器 (^),光束就会停止;取而代之的是,新的超光速粒子束会被分束,从分束器的正左侧和正右侧继续向下移动。

于是,从 S 发射的超光速离子束最后会被分束成这样:

.......S.......
.......|.......
......|^|......
......|.|......
.....|^|^|.....
.....|.|.|.....
....|^|^|^|....
....|.|.|.|....
...|^|^|||^|...
...|.|.|||.|...
..|^|^|||^|^|..
..|.|.|||.|.|..
.|^|||^||.||^|.
.|.|||.||.||.|.
|^|^|^|^|^|||^|
|.|.|.|.|.|||.|

part1 的问题是,超光速离子束被分束了几次?

当光束 (|) 往下碰到分束器 (^) 的时候,就会被分束,所以问题可以变成:

图中存在多少个这样的分束器:

|
^

统计这种结构的分束器的数量,对应的就是超光速离子束被分束的次数。

只要遍历每一行,对其中的每个分束器 (^) 判断它上面是否存在离子束 (|),如果存在,就累计数量。

在遍历时,用一个变量维护上一行的离子束 (|) 状态,就可以方便地进行比较了。


part2 的问题是,实际只有一个超光速粒子,当它碰到分束器的时候,可能往左,也可能往右,统计最终有多少条路径可以走到底部。

例如粒子可以有一下几种走法:

  • 一直沿着分束器的左边走

    .......S.......
    .......|.......
    ......|^.......
    ......|........
    .....|^.^......
    .....|.........
    ....|^.^.^.....
    ....|..........
    ...|^.^...^....
    ...|...........
    ..|^.^...^.^...
    ..|............
    .|^...^.....^..
    .|.............
    |^.^.^.^.^...^.
    |..............
    
  • 碰到分束器,交替地向左向右走

    .......S.......
    .......|.......
    ......|^.......
    ......|........
    ......^|^......
    .......|.......
    .....^|^.^.....
    ......|........
    ....^.^|..^....
    .......|.......
    ...^.^.|.^.^...
    .......|.......
    ..^...^|....^..
    .......|.......
    .^.^.^|^.^...^.
    ......|........
    

总之路径很多,最终能走到底部都算。

粒子时而往左,时而往右,看起来有非常多的组合。

但仔细一想,对于粒子而言,它只有 3 种选择:

  • 要么穿过 . 向下走 (↓)
  • 要么碰到 ^ ,从左边往下走 (⮦)
  • 要么碰到 ^ ,从右边往下走(⮧)

每往下走一次,粒子都要再做一次选择,直到走到底部。

为了更好的观察规律,可以从数据量较小的情况观察,例如只看前 5 行:

.......S.......
...............
.......^.......
...............
......^.^......

上面的图中,总共有 4 种路径可以走到底,分别是:

.......S.......
.......|.......
......|^.......
......|........
.....|^.^......
.......S.......
.......|.......
......|^.......
......|........
......^|^......
.......S.......
.......|.......
.......^|......
........|......
......^|^......
.......S.......
.......|.......
.......^|......
........|......
......^.^|.....

如何统计路径呢?可以一步步看看。

为了方便描述,用 diagram 表示这个图,diagram[0] 表示第一行,diagram[0][0] 表示第一行的第一列的位置。

用 timelines[x][y] 来表示在 x 行 y 列时,有多少的路径。

粒子从 S (diagram[0][7]) 出发,只能往下走,走到了 diagram[1][7]。

.......S.......
.......|.......
.......^.......
...............
......^.^......

此时 timelines[0][7] = timelines[1][7] 。

然后粒子碰到了一个分束器,可以向左,走到 diagram[2][6] ;也可以向右,走到 diagram[2][8] 。

.......S.......
.......|.......
......|^.......
...............
......^.^......
.......S.......
.......|.......
.......^|......
...............
......^.^......

此时 timelines[0][7] = timelines[1][7] = timelines[2][6] + timelines[2][8] 。

也就是说:

  • 当没有碰到分束器时:

    timelines[x][y] = timelines[x + 1][y]

    即往下走一步的路径数量。

  • 当碰到分束器时:

    timelines[x][y] = timelines[x + 1][y - 1] + timelines[x + 1][y + 1]

    即向左走和向右走的路径数量之和。

粒子继续往下走,式子可以一直写下去:

timelines[0][7] =
timelines[1][7] =
timelines[2][6] + timelines[2][8] =
timelines[3][6] + timelines[3][8] =
timelines[4][5] + timelines[4][7] + timelines[4][7] + timelines[4][9] =
1 + 1 + 1 + 1 =
4

当走到最后一行的时候,粒子已经走到走到底了,就只有一条路径,所以 timelines[4][y] = 1。

可以发现这是把一个大的问题,拆成一个更小的问题,直到这个问题知道确切的答案。可以利用递归实现,递归结束条件就是粒子走到了最后一行。

但是当我用这样的方法实现的时候,我发现代码执行了很久都没有结果。分析一下时间复杂度发现,当粒子到一个分束器,就会一分为二, 假设粒子在每一行都碰到分束器,相当于每往下走一行,计算量就会翻倍。假设有 N 行的话,时间复杂度就是 2 的 N 次方,是一个指数,所以随着 N 增加,时间复杂度会急剧上升。

观察式子,会发现 timelines[4][7] 被重复计算了,可以利用一个哈希表记录被计算过的位置的值,这样,每个位置只会被计算一次,假设有 N 个位置,时间复杂度就是 N,就会快很多了。

具体代码见:day7/solution.py

Webmentions (加载中...)

如果你想回应这篇文章,你可以在你的文章中链接这篇文章,然后在下面输入你的文章的 URL 并提交。你的回应随后会显示在此页面上(如果是垃圾信息我会屏蔽)。如果要更新或删除你的回应,请更新或删除你的文章,然后再次输入该文章的 URL 并提交。(了解有关 Webmention 的更多信息。)


    创建于: 2025-12-08 Mon 11:22

    修改于: 2025-12-08 Mon 11:23

    许可证: 署名—非商业性使用—相同方式共享 4.0

    支持我: 用你喜欢的方式


    文章来源: https://taxodium.ink/aoc-2025-day-7.html
    如有侵权请联系:admin#unsafe.sh