一小拨混混儿正等在Frank的办公室门口。他们本想混进去,但老远就被Frank认出来了。他们中的一个坐在长凳上,一边装作读报纸,一边来来回回打量着整条街。另外三个站在角落旁,正大声讨论最近的体育赛事。Frank走近一听才发现他们在假装聊天:其中一人大声抱怨皇家马球比赛的裁判,另一个在说即将到来的赛马内幕,剩下那个只会时不时地念叨一声“体育比赛”。
只有那个探子成功隐蔽了自己。她等在街对面,随意地靠在墙上。要不是曾经追捕过她,Frank大概就彻底忽略掉她了。她很厉害,或者说,主要是那些小混混儿太差劲了。
Frank没有停下来,接着拐进了小巷子。那群Vinettee集团的小混混儿们正等着他,所以他没法回办公室。略作思考后,他去了一间警察安全屋。离得不远,也很久没有人用过了。幸运的话,他没准还能想起门锁密码。
离安全屋还剩半个街区的时候,Frank听见他身后传来了喊叫和重重的脚步声。那个探子一定是通知他们了。
“Frank!”一个强壮的恶棍喊道,“我们只是想和你聊一聊。”
其他人都笑了起来,让人觉得这句话好像合情合理,难以怀疑他们的本来动机。Frank拔腿就跑,身后的脚步声也跟了上来。
Frank突然向左急转弯,跑进了一条狭窄的小巷。Frank对这里非常熟悉,他一定要想办法甩掉这些恶棍。他现在必须尽快找到安全屋,因为安全屋门上有把密码锁,所以要进屋需要花点时间,除非他能在第一次就试对密码。
Frank从小巷走到了Flag街上,快速转弯,进入角落里的商店中。他假装在儿童服装货架周围转悠着,同时还向窗外看着。在这个位置能够很好地对商店外边进行监视。
没过一会,恶棍们就蜂拥到了街上,胡乱地到处看。间谍紧跟其后并发布命令。她将恶棍分成两组,分别沿着街道的两个方向继续寻找,而她则在胡同的口等着。
Frank一刻也不敢停留。他抓紧时间从商店出来,然后朝着另一扇门走去,这扇门通向一个小巷子。间谍就在Frank身边十步远的地方,背对着他。Frank又悄悄地从巷子里撤了回来,向安全屋走去。假如他足够走运,那些恶棍没想到去向店员打听什么的话,他便能争取到更多的时间了。
在安全屋的门口,Frank尝试着解锁。他先尝试1-1-1。不可否认,这是一个简单的密码。锁没能打开。
Frank咒骂起来,从他上次到过这里后,一定有人更换过密码。Frank现在面临两种选择,一种是继续尝试密码开锁,但是这可能需要花费很长时间;第二种是去找另一个地方藏身。但他再也想不到另一个安全并且恶棍找不到的地方了,于是他又转身继续面对这把锁。
由于时间非常紧张,Frank需要提高效率。密码由三个数字组成,每个数字可能是1~20中的任意一个,所以他面对8000种可能的组合。Frank此刻没有时间进行广度优先搜索或深度优先搜索。相反,他必须依靠有限的搜索和一些猜测来破解密码。此刻,他必须相信自己的直觉。Frank从口袋里取出记录优先队列的纸,擦干净,开始把尝试的每一种组合记下。他为每一个密码组都添加了一个优先级——是他对每组密码可能性的直觉。他开始尝试警察们的常用组合:
1-2-3
1-1-2
1-3-5
Frank将这三个组合的优先级都设为10。
然后,他开始尝试由三个重复数字组成的三元组。如果密码曾经是1-1-1,为什么不使用2-2-2?安全屋很少被使用,所以它很可能只使用简单密码。他列出了19个未尝试过的三元组,并赋予优先级5,现在优先队列中已有22个待尝试的密码。
接下来,他通过负责安全屋警察的生日增加了六个可能的密码组,并赋予优先级8。他还添加了此时能记起的其他警察生日的密码组,并赋予优先级2。
最后,他添加了单词RUN并赋予优先级1。他知道,如果试到该项,就是时候放弃了,他必须找到另一个地方藏身。
现在优先队列中有32个密码组。需要把每个密码组都尝试一遍。在顶部是最高优先级的密码组:1-2-3。Frank试了一下,锁并没有开。
他大骂一声并把刚才尝试过的密码组从优先队列中删除,此时新的最高优先级的密码组便会自动出现在优先队列的顶部。
在尝试下一个密码组之前,Frank突然有个想法。他们会把旧密码做一些变化后再使用吗?他知道很多警察使用一个组合作为他们的储物柜的密码,并把这个密码颠倒一下作为行李箱的密码。负责安全屋的警察是否也会这样做?Frank把3-2-1这个密码组添加到他的优先队列的底部,并赋予优先级9。
1-1-2和1-3-5都不正确,所有优先级为10的密码组都尝试过了。Frank把它们颠倒后的密码组2-1-1和5-3-1也添加到优先队列的底部,并赋予优先级9。
Frank从优先队列顶部取出下一个优先级最高的密码组3-2-1。这是他刚刚添加的颠倒后的密码组之一。这正是优先队列的魔力,无论你以什么样的先后顺序去添加密码组,你总能得到队列当中优先级最高的那个。
锁开了,密码是5-3-1,密码组中优先级为9的一个。Frank缓缓地叹了一口气,瞥了一眼,没有Vinettee集团的迹象。他现在安全了。
警用算法导论:数据结构和搜索
节选自Drecker教授讲义
正如我们在整个学期的讲座中所讨论的,我们使用的数据结构可以影响算法的实现方式和效率。在深度优先搜索和广度优先搜索的讲义中,我们研究了栈和队列之间的差异,以及它们是如何影响搜索顺序的。在最佳优先搜索中,使用优先队列是数据结构影响算法效率的另一个很好的例子。
从概念上说,最佳优先搜索类似于广度优先搜索和深度优先搜索——在算法的每一步,都会选择一个新状态来进行探索。它们之间最关键的区别在于如何安排新产生的状态的探索次序。使用优先队列可以让我们每次都更有效地挑选出最接近目标解的状态。最佳优先搜索与优先队列是一对完美的组合,是一组极其高效的“数据结构+算法”的范例。