Skip to content

Commit

Permalink
day 21: readme todo
Browse files Browse the repository at this point in the history
  • Loading branch information
livexia committed Dec 21, 2023
1 parent 0e799cd commit 7943c77
Showing 1 changed file with 35 additions and 0 deletions.
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,3 +714,38 @@ https://en.wikipedia.org/wiki/Shoelace_formula
观察给定的输入,可以发现 `rx` 仅依赖 `vd` ,而 `vd` 则依赖于 `rd bt fv``pr``vd rd bt fv``pr` 都为 *Conjunction* 模块,所以如果 `rx` 要接收到低位,那么 `vd` 要发出低位,则 `vd` 的四个输入模块都必须发出高位,那么当 `rd bt fv``pr` 都发出高位时,`rx` 就能接收到低位。因为 rx 仅依赖于 `vd` ,那么求 `rx` 和求 `vd` 的求解空间应当是一样大的,所以就需要考虑 `vd` 依赖的四个模块,如果这四个模块存在一定的规律那么就可以将问题划分,减少求解空间。根据分析输入所得到的依赖关系,**利用代码计算这四个模块发出高位所需要的按键次数**,如果循环出现,那么说明存在规律,最后只需要计算四个模块发出高位次数的最小公倍数即是题解。

虽然第二部分涉及的代码是同第一部分一致的,但是在**利用代码计算这四个模块发出高位所需要的按键次数**的时间点很重要,因为 vd 这四个模块,所以要在经过 vd 模块就检测这四个模块发出的高低位,如果在按完一次按钮的最后,再检测这四个模块,那就可能无法检测到这四个模块的状态变化。这个细节也是为何我虽然知晓求解方法,但是依旧耗费了不少时间的原因。

## Day 21(TODO)

### 第二部分

- 可以从一个位置进行上下左右的移动,要计算从位置 `S` 开始,经过 `step` 次移动,可以到达位置的数,令函数 `f(step)` 表示该问题
- 同时令 `d(step)` 表示从从位置 `S` 开始,经过 `step` 次不回头的移动,可以到达位置的数
- 即从 `S` 出发的最短路径长度为 `step` 的路径数
- 可以发现 `f(step) = d(step) + f(step -2)`
- 当从 `S` 出发经过 `step - 2` 次移动,如果剩余的 `2` 次移动允许回头,那么两次移动可以被消除(向左,再向右)
- 所以所有 `f(step -2)` 的终点都包含在 `f(step)`
- 同样的 `f(step - 4)``f(step - 2)` 包含
- 同时 `f(step - 1)` 中的任何终点都不可能被 f(step) 包含,因为其中的位置,只需要移动一次就可以成为 `f(step)` ,而移动一次却不可能实现原地不动
- 如果网格中不存在任何的石头,那么 d(step) 的终点将是以 S 为中心的一个菱形的边,边上的任意位置与 S 的最短距离是曼哈顿距离
- 根据 `f(step) = d(step) + f(step -2)`
- 对于任意的偶数 `step``f(step) = d(step) + d(step - 2) + … + d(0)`
- 对于任意的奇数 `step``f(step) = d(step) + d(step - 2) + … + d(1)`
- 第二部分的网格是无限网格,所以就算知道 `f(step)` 的计算公式也不能减少多少计算量
- 参考 Reddit 上的解法,通过求解二次函数的系数,确定二次函数,再计算最终结果即可。
- https://old.reddit.com/r/adventofcode/comments/18nevo3/2023_day_21_solutions/
- 实际的输入中,网格的四边都为空,同时起始点 `S` 位于的行和列都为空,那么从 `S` 到四边上位置的最短路径长度即是二者之间的曼哈顿距离
- 同时 `S` 位于网格的正中央,那么 S 到四角的最短距离长度刚好为网格的边长 `width`(长宽相等)
- 所以从一个网格的 `S` 出发,在上下左右四个方向移动网格边长的距离 `width`,就会抵达相邻网格的 `S`
- 当 S 移动 `width` 时 覆盖了 1 个原始网格
- 当 S 移动 `2 * width` 时 覆盖了 5 个原始网格
- 当 S 移动 `3 * width` 时 覆盖了 13 个原始网格
- 当 S 移动 `4 * width` 时 覆盖了 25 个原始网格
- [https://www.wolframalpha.com/input?i=quadratic+fit+{{1%2C+1}%2C+{2%2C+5}%2C+{3%2C+13}%2C+{4%2C+25}}](https://www.wolframalpha.com/input?i=quadratic+fit+%7B%7B1%2C+1%7D%2C+%7B2%2C+5%7D%2C+%7B3%2C+13%7D%2C+%7B4%2C+25%7D%7D)
- 网格的覆盖是随着移动的距离二次增长的
- 第二部分要求计算移动距离 `26501365` 的位置个数
- 输入网格边长为 `131`,恰好 `26501365 = 131 * 202300 + 65`
- 可以计算出 65 次, 65 + 131 次 和 65 + 131 * 2 次移动距离时到达的位置数
- 假设二次函数为 $f(x) = ax^2 + bx +c$ 且 $x = (step - 65) / 131$
- 那么得到 f(0) , f(1) 和 f(2) 的值就可以计算出系数 a b c
- 再计算 f(202300) 即是结果

0 comments on commit 7943c77

Please sign in to comment.