关于炒饭每日挑战-猜铁上海的一些研究

炒饭每日挑战-猜铁上海

背景知识

「猜铁」规则说明
每天北京时间 0 点题目更新。
您有 6 次机会来尝试猜出一个地铁站。
在猜测后,您可以看到今日地铁站与所猜测地铁站的异同点和关联。
(具体地,会给出今日地铁站与所猜测地铁站的:1.所在区是否相同 2.是否位于同一条线路上 3.最少换乘次数 4.最短距离 5.投用时间先后关系,实际上 2 是包含于 3 的)
目标换乘和目标距离是独立的,分别指到隐藏站点的最少需要换乘多少次,到隐藏站点最少距离多少个站点。


提出问题

以下三个问题并非按照提出顺序排列,而是按照我在代码中实现顺序排列。

  • 回答所给的信息是否过多了?具体地,若只回答最少换乘次数和最短距离,是否存在一种 ADP 的方案(可以根据上次猜测的信息决定下一次的猜测),使得两次猜测后获得的信息足以确定隐藏站点?
  • 是否存在一种 ADP 的方案,使得两次猜测后获得的信息足以确定隐藏站点?
  • 是否存在一种 non-ADP 的方案(必须先给出两次猜测的站再得到回答),使得两次猜测后获得的信息足以确定隐藏站点?

由于我地理不好,后两个问题最终也只考虑换乘次数、距离、投用时间,不考虑所在区。


前期准备工作

根据百度百科的信息,我整理了每一条线路对应站点的名称与投用时间(例如,对于人民广场站,一号线对应站点投用于 1995 年,二号线对应站点投用于 2000 年,八号线对应站点投用于 2007 年)。
特别地,十三号线各站点的投用时间众口难调,此处采用手动测试的炒饭每日挑战的数据:马当路站 2010,世博会博物馆站 2010,世博大道站 2016(其实很奇怪?)。
特别地,对于有支线的线路,本文只考虑百度百科中标注的所谓主线,且支线理应不存在市内换乘的情形,因而不构成影响。
叠甲:数据截止到 2024 年末,且只考虑一至十八号线。
以下采用 C++ 语言进行数据分析与处理。以上数据被我保存在 metro_table.in 中。


大体思路

我对所有站点采用了两种不同的编号方式:第一种为实际站点,用 map<string,int>存储,即名称-index,共 390 个(注意到四号线浦电路站已改名为向城路站,解决了历史遗留问题);第二种为虚拟站点,每条线路的对应站各记录一次(例如,对于人民广场站,一号线、二号线、八号线的对应虚拟站点各记录一次),共 497 个。
第二种编号在我的实现中计算更加方便,而最终可调用的函数则基于第一种编号。


具体实践

核心在于计算最少换乘次数与最短距离。(Warning:如果你看了我的代码实现,会发现其中类型 \(1\) 代表距离,类型 \(2\) 代表换乘,与下文的叙述相反)
考虑对于虚拟站点集 \(V\)(note that \(|V|=497\)),建立两个无向图 \(G_1(V,E_1),G_2(V,E_2)\),分别用于计算最少换乘次数与最短距离。
对于同一条线路上的相邻虚拟站点 \(p,q\),连边 \(e_1,e_2 = p \sim q\),边权分别为 \(0,1\);对于实际为同一站的虚拟站点 \(p,q\),连边 \(e_1,e_2 = p \sim q\),边权分别为 \(1,0\)
对于不满足上述两种情况的站点对 \(p,q\),理应不存在连边,而实现中边权记为一个较大的数。
此时对 \(G_1,G_2\) 使用 \(\text{Floyd-Warshall}\) 算法即可求出 \(\forall 1 \le p,q \le 497\)\(p,q\)\(G_1,G_2\) 中分别的最短路长度 \(dst_{1}(p,q),dst_{2}(p,q)\)
设计三种函数(传入值为两个整数,为第一种编号方式下的站点):\(\text{calc}_1(i,j)\) 返回 \(i,j\) 之间的最少换乘次数(特别地,需要枚举 \(i,j\) 分别对应的虚拟站点 \(p,q\),并求出 \(dst_{1}(p,q)\) 的最小值);\(\text{calc}_2(i,j)\) 返回 \(i,j\) 之间的最短距离;\(\text{calc}_3(i,j)\) 返回 \(i,j\) 投用年份的比较,其中返回 \(0,1,2\) 分别代表 \(i\) 同年于、早于、晚于 \(j\)

解决问题(欢迎查错!)

对于第一个问题,以下循环、运算由外向内:

  • 枚举第一次猜测的站 \(i\)
  • 枚举 \((t,d) \in \mathbb{N}_{\le 3} \times \mathbb{N}_{\le 100}\),分别代表从 \(i\) 出发最少换乘 \(t\) 次、最短距离为 \(d\)\(\text{t}\color{red}\text{yf}\):注意到从人民广场站出发可不多于一次换乘到达任意站);
  • 枚举以求出满足上述限制的站点编号(即 \(\text{calc}_1(i,\cdot)=t\)\(\text{calc}_2(i,\cdot)=d\)),记录在数组 \(v\) 中;
  • 枚举第二次猜测的站 \(j\)
  • 遍历数组 \(v\),若存在 \(k_1 \neq k_2 \in V\) 使 \((\text{calc}_1(j,k_1),\text{calc}_2(j,k_1))=(\text{calc}_1(j,k_2),\text{calc}_2(j,k_2))\),则第一次猜测 \(i\),第二次猜测 \(j\) 不是合法的策略,由于它们不能分辨 \(k_1,k_2\)
  • 遍历结束后,若不存在这样的 \(k_1,k_2\),则在第一次猜测 \(i\) 且得到的回答是 \((t,d)\) 的情况下,第二次猜测 \(j\) 是一个合理的选择。

遗憾的是,对于任意的 \(i\),都存在一组 \((t,d)\) 使得不存在能分辨出所有情形的 \(j\)
因此我给出的答案是:不存在这样的方案。


对于第二个问题,以下循环、运算由外向内:

  • 枚举第一次猜测的站 \(i\)
  • 枚举 \((t,d,op) \in \mathbb{N}_{\le 3} \times \mathbb{N}_{\le 100} \times \mathbb{N}_{\le 2}\),分别代表从 \(i\) 出发最少换乘 \(t\) 次、最短距离为 \(d\)、投用年份比较结果为 \(op\)
  • 枚举以求出满足上述限制的站点编号(即 \(\text{calc}_1(i,\cdot)=t\)\(\text{calc}_2(i,\cdot)=d\)\(\text{calc}_3(i,\cdot)=op\)),记录在数组 \(v\) 中;
  • 枚举第二次猜测的站 \(j\)
  • 遍历数组 \(v\),若存在 \(k_1 \neq k_2 \in V\) 使 \((\text{calc}_1(j,k_1),\text{calc}_2(j,k_1),\text{calc}_3(j,k_1))=(\text{calc}_1(j,k_2),\text{calc}_2(j,k_2),\text{calc}_3(j,k_2))\),则第一次猜测 \(i\),第二次猜测 \(j\) 不是合法的策略,由于它们不能分辨 \(k_1,k_2\)
  • 遍历结束后,若不存在这样的 \(k_1,k_2\),则在第一次猜测 \(i\) 且得到的回答是 \((t,d,op)\) 的情况下,第二次猜测 \(j\) 是一个合理的选择。

有趣的是,程序给出的可以作为第一次猜测的 \(i\) 不少。不过 given that 上一个问题中往往是有两三个站难以分辨,这个结果是可以接受的。
因此我给出的结论是:这样的方案应当有非常多。


对于第三个问题,以下循环、运算由外向内:

  • 枚举第一次猜测的站 \(i\),第二次猜测的站 \(j\)
  • 枚举 \((t,d,op) \in \mathbb{N}_{\le 3} \times \mathbb{N}_{\le 100} \times \mathbb{N}_{\le 2}\),分别代表从 \(i\) 出发最少换乘 \(t\) 次、最短距离为 \(d\)、投用年份比较结果为 \(op\)
  • 枚举以求出满足上述限制的站点编号(即 \(\text{calc}_1(i,\cdot)=t\)\(\text{calc}_2(i,\cdot)=d\)\(\text{calc}_3(i,\cdot)=op\)),记录在数组 \(v\) 中;
  • 遍历数组 \(v\),若存在 \(k_1 \neq k_2 \in V\) 使 \((\text{calc}_1(j,k_1),\text{calc}_2(j,k_1),\text{calc}_3(j,k_1))=(\text{calc}_1(j,k_2),\text{calc}_2(j,k_2),\text{calc}_3(j,k_2))\),则第一次猜测 \(i\),第二次猜测 \(j\) 不是合法的策略,由于它们不能分辨 \(k_1,k_2\)
  • 所有 \((t,d,op)\) 枚举结束后,若均不存在这样的 \(k_1,k_2\),则在第一次猜测 \(i\),第二次猜测 \(j\) 是一个合理的选择。

遗憾的是,对于任意的 \(i,j\),都存在一组 \((t,d,op)\) 使得存在至少两个站不能被分辨。
因此我给出的答案是:不存在这样的方案。

不过我心里还是不踏实。希望有心人来查错!!!

posted @ 2025-02-10 13:09  孤独的电磁场  阅读(356)  评论(0)    收藏  举报