利用Duckdb求解Advent of Code 2025第11题 问题路径

原题地址
— 第 11 天:反应堆 —
你听到工厂地板上的一个舱口传来响亮的哔哔声,于是决定去查看一下。里面有几根大型电缆管道和一把梯子。

顺着梯子爬下去,你发现了哔哔声的来源:一个为上方工厂供电的大型环形反应堆。这里的精灵们正匆忙地在反应堆和一个附近的服务器机架之间跑来跑去,显然是在试图修复什么。

一位精灵注意到你并急忙跑过来。"你来得正好!我们刚安装了一个新的服务器机架,但我们一直无法让反应堆与它通信!"你环顾房间,看到从服务器机架到反应堆连接着一堆乱七八糟的电缆和设备。她匆匆离开,片刻后带着一份设备及其输出的列表(你的谜题输入)回来了。

例如:

aaa: you hhh
you: bbb ccc
bbb: ddd eee
ccc: ddd eee fff
ddd: ggg
eee: out
fff: out
ggg: out
hhh: ccc fff iii
iii: out

每行给出一个设备的名称,后跟其输出连接到的设备列表。因此,bbb: ddd eee 意味着设备 bbb 有两个输出,一个连接到设备 ddd,另一个连接到设备 eee

精灵们相当确定问题不是由任何特定设备引起的,而是由数据在设备之间沿着某些特定路径流动触发的。数据只能通过其输出从一个设备流出;它不能反向流动。

分配好工作后,精灵们希望你把重点放在从你旁边的设备(一位精灵匆忙贴上一个只写着 you 的标签)开始,到反应堆主输出(即标有 out 的设备)结束的设备上。

为了帮助精灵们找出是哪条路径导致了问题,他们需要你找到从 youout 的每一条路径。

在这个例子中,以下是从 youout 的所有路径:

  1. 数据可以从 you 连接到 bbb,然后从 bbbddd,然后从 dddggg,然后从 gggout
  2. 数据可以连接到 bbb,然后到 eee,然后到 out
  3. 数据可以到 ccc,然后到 ddd,然后到 ggg,然后到 out
  4. 数据可以到 ccc,然后到 eee,然后到 out
  5. 数据可以到 ccc,然后到 fff,然后到 out

总共有 5 条不同的路径从 you 通向 out

有多少条不同的路径从 you 通向 out

— 第二部分 —
部分归功于你的分析,精灵们对问题有了一些了解。他们现在知道有问题的数据路径会同时经过 dac(数模转换器)和 fft(执行快速傅里叶变换的设备)。

他们仍然不确定哪条具体路径是问题所在,因此现在需要你找到从 svr(服务器机架)到 out 的每一条路径。然而,你找到的路径都必须同时访问 dacfft(顺序任意)。

例如:

svr: aaa bbb
aaa: fft
fft: ccc
bbb: tty
tty: ccc
ccc: ddd eee
ddd: hub
hub: fff
eee: dac
dac: fff
fff: ggg hhh
ggg: out
hhh: out

这份新的设备列表包含许多从 svrout 的路径:

  1. svr,aaa,fft,ccc,ddd,hub,fff,ggg,out
  2. svr,aaa,fft,ccc,ddd,hub,fff,hhh,out
  3. svr,aaa,fft,ccc,eee,dac,fff,ggg,out
  4. svr,aaa,fft,ccc,eee,dac,fff,hhh,out
  5. svr,bbb,tty,ccc,ddd,hub,fff,ggg,out
  6. svr,bbb,tty,ccc,ddd,hub,fff,hhh,out
  7. svr,bbb,tty,ccc,eee,dac,fff,ggg,out
  8. svr,bbb,tty,ccc,eee,dac,fff,hhh,out

然而,只有 2 条从 svrout 的路径同时访问了 dacfft

找到所有从 svr 通向 out 的路径。其中有多少条路径同时访问了 dacfft

第一题很简单,基本的递归CTE就解决了

with recursive t as(
select
'aaa: you hhh
you: bbb ccc
bbb: ddd eee
ccc: ddd eee fff
ddd: ggg
eee: out
fff: out
ggg: out
hhh: ccc fff iii
iii: out' t)
, b as(select row_number()over()rn ,substr(b, 1, 3)be, unnest(string_split(substr(b, 6), chr(32)))ed from(select unnest(string_split(t, chr(10)))b from t))
,a as(select 1 lv, [be,ed]m from b where be='you'
union all
select 1+lv, m||[b.ed]  from a, b
where b.be=m[-1] and b.be<>'out' and lv<10)
select count(*)from a where m[1]='you' and m[-1]='out';

第二问貌似和第一问没什么区别,就是换个头尾,加上判断中间,示例数据也确实很容易通过了。

with recursive t as(
select
'svr: aaa bbb
aaa: fft
fft: ccc
bbb: tty
tty: ccc
ccc: ddd eee
ddd: hub
hub: fff
eee: dac
dac: fff
fff: ggg hhh
ggg: out
hhh: out' t)
, b as(select row_number()over()rn ,substr(b, 1, 3)be, unnest(string_split(substr(b, 6), chr(32)))ed from(select unnest(string_split(t, chr(10)))b from t))
,a as(select 1 lv, [be,ed]m from b where be='svr'
union all
select 1+lv, m||[b.ed]  from a, b
where b.be=m[-1] and b.be<>'out')
select count(*)from a where m[1]='svr' and m[-1]='out' and 'dac' in m and 'fft' in m;

但是用于正式输入数据,却算不出来,数据的分布决定的。估计不能直接连,要用数学方法计算。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值