原文地址:https://adventofcode.com/2024/day/25
第 25 天:代码编年史
在无计可施且时间紧迫的情况下,历史学家们一致认为应该最后再去检查一次首席历史学家的办公室,以防他在你们没注意的时候回去了。
当你们到达那里时,惊讶地发现他办公室的门锁上了!你们能听到里面有人,但敲门没有得到任何回应。这一层的锁都是昂贵花哨的五针虚拟弹子锁的虚拟版本,于是你联系北极安全部门,看看他们是否能帮忙开门。
不幸的是,他们已经弄不清安装了哪些锁以及哪些钥匙与之匹配,所以他们最多只能把你所在楼层的所有锁和所有钥匙的示意图发给你(你的谜题输入)。
这些示意图采用了一种加密的文件格式,但其中确实包含制造商信息,于是你查找到了他们的支持电话。
“我们的虚拟五针弹子锁产品?那是我们最昂贵的型号!比——安全得多——” 你解释说你需要开门,而且时间不多了。
“嗯,不真正把钥匙插入锁中尝试(由于量子隐变量),你无法知道一把钥匙是否能打开一把锁,但你可以排除一些钥匙/锁的组合。”
“这个虚拟系统很复杂,但其中一部分确实是对五针弹子锁的粗略模拟,这主要是出于市场营销的原因。如果你查看示意图,就能判断出一把钥匙是否可能插入一把锁。”
他给你传输了一些示例示意图:
#####
.####
.####
.####
.#.#.
.#...
.....
#####
##.##
.#.##
...##
...#.
...#.
.....
.....
#....
#....
#...#
#.#.#
#.###
#####
.....
.....
#.#..
###..
###.#
###.#
#####
.....
.....
.....
#....
#.#..
#.#.#
#####
“锁的示意图是顶行填满(#)且底行为空(.);钥匙的示意图则是顶行为空且底行填满。如果你仔细观察,会发现每个示意图实际上是一组高度不同的列,这些列要么从顶部向下延伸(对于锁),要么从底部向上延伸(对于钥匙)。”
“对于锁,这些就是锁针本身;你可以将示意图中的锁针转换为高度列表,每列一个高度。对于钥匙,这些列构成了钥匙与锁针对齐时的形状;这些也可以转换为高度列表。”
“所以,你可以说第一把锁的锁针高度是 0,5,3,4,3:”
#####
.####
.####
.####
.#.#.
.#...
.....
“或者说第一把钥匙的高度是 5,0,2,1,3:”
.....
#....
#....
#...#
#.#.#
#.###
#####
“这些看起来应该能配合;在前四列中,锁针和钥匙没有重叠。然而,这把钥匙不能用于这把锁:在最右边的列中,锁针与钥匙发生了重叠,你能知道这一点是因为在该列中,锁的高度和钥匙的高度之和超过了可用空间。”
“所以无论如何,你可以通过测试每把钥匙与每把锁来缩小需要尝试的钥匙范围,这意味着你需要检查……等等,你有多少把锁?但是唯一有那种规模安装的地方是在北——” 你挂断了电话。
在这个例子中,将两把锁转换为锁针高度得到:
0,5,3,4,3
1,2,0,5,3
将三把钥匙转换为高度得到:
5,0,2,1,3
4,3,4,0,2
3,0,2,0,1
然后,你可以尝试每把钥匙与每把锁的匹配:
- 锁 0,5,3,4,3 和钥匙 5,0,2,1,3:在最后一列重叠。
- 锁 0,5,3,4,3 和钥匙 4,3,4,0,2:在第二列重叠。
- 锁 0,5,3,4,3 和钥匙 3,0,2,0,1:所有列都匹配!
- 锁 1,2,0,5,3 和钥匙 5,0,2,1,3:在第一列重叠。
- 锁 1,2,0,5,3 和钥匙 4,3,4,0,2:所有列都匹配!
- 锁 1,2,0,5,3 和钥匙 3,0,2,0,1:所有列都匹配!
所以,在这个例子中,没有任何列发生重叠的独特锁/钥匙对的数量是 3。
分析你的锁和钥匙示意图。有多少个独特的锁/钥匙对能在任何列都不重叠的情况下匹配?
我的duckdb sql解答
with t as(select row_number()over()rn , c from read_csv('input.txt', header=0)t1(c))
, t2 as(select rn//8 a, rn%8 b, [case substr(c, i, 1) when '#' then 1 when '.' then 0 end for i in range(1, 6)]c from t)
, tl as( select a,'L' ty from t2 where c=[1, 1, 1, 1, 1] and b=1 )
, tk as( select a,'K' ty from t2 where c=[1, 1, 1, 1, 1] and b=7 )
, t3 as( select t2.a,ty, sum(c[1])s1,sum(c[2])s2,sum(c[3])s3,sum(c[4])s4,sum(c[5])s5,from t2,(from tl union all from tk)t4 where t2.a =t4.a and b between 2 and 6 group by t2.a,ty )
select count()/*distinct t3.a, t5.a*/ from t3, t3 t5 where t3.ty='L' and t5.ty='K' and t3.s1+t5.s1<6 and t3.s2+t5.s2<6 and t3.s3+t5.s3<6 and t3.s4+t5.s4<6 and t3.s5+t5.s5<6;
t:读入外部输入文件并编制行号
t2:依据行号划分图案编号和图案内行号,并把每行图案转为数字数组
tl:筛选出锁的图案编号
tk:筛选出钥匙的图案编号
t3:计算每个图案的柱子长度数组
最终,对锁和钥匙交叉连接,找出柱子长度之和不存在6及以上的配对总数

1597

被折叠的 条评论
为什么被折叠?



