夺冠秘诀?2024华为软件精英挑战赛全球总冠军这样复盘比赛经验
发表于 2024-05-07 14:45:55

日前,2024第十届华为软件精英挑战赛-“普朗克计划”全球总决赛及颁奖典礼圆满落幕。大赛吸引了来自全球800多所高校、超5700支队伍、近30000名大学生报名参赛,历时两个月的激烈角逐,经过八大赛区区域初赛、区域复赛、全球总决赛等环节的层层考验。最终,京津东北赛区来自哈尔滨工业大学的“元梦之星”队获得全球总决赛冠军。作为连续两届华为软挑大赛的获奖选手,来自哈尔滨工业大学的优秀选手陈月东撰文分享其赛队参赛体验,包括参赛初衷、解题思路及方案、比赛收获等。

1.感想

比赛初衷

今年是第二年参加软挑,在去年第一次参加软挑见识到了SimpleDemo和冠军队的强大实力,很希望今年能和去年的冠军队再战一回(去年跟冠军队还没PK就被刷下来了),也希望能借这个比赛再次挑战一下自己,因此报名开始没几天我就报名参加这个比赛了。

赛题介绍

智慧港口是各城市贸易港口的重点建设与发展方向。华为云可提供全方位智能算法技术平台助力智慧港口建设。本次赛题方向和内容选自于华为云智慧港口真实业务场景,邀请参赛选手为港口运输公司提供货物智能搬运、货船智能泊靠等算法,以助力港口运输公司最大化提升工作效率并降低装卸成本。

初赛

初赛我们看到赛题的第一眼,感觉在不考虑轮船的情况下,跟去年的赛题非常类似。因此前几天我们都在研究去年公布的SimpleDemo,以期望能借鉴一些思路。最后我们初赛代码沿用了SimpleDemo的整体框架,只是特殊修改了机器人决策函数和避让算法,轮船则单独设计了一种针对初赛赛题的特殊决策,并配以相应的参数。在初赛正式赛期间,通过调节参数,我们顺利地拿下了初赛全国第一名。

复赛

复赛主要新增两个修改点,一个是船和机器人需要自己购买,另一个是船需要自己控制。我们最终在初赛代码的基础上对机器人的决策进行微调(最后关头尽量和船配合,以期望获得最高分),修改了轮船决策函数,增加了轮船的寻路和避让策略,且增加了动态购买机器人和轮船的决策函数,并配上相应的参数。

在复赛正式赛期间,赛题新增了一种机器人,虽然载货量是2倍,但是价格是普通机器人价格的2倍还多1000,我们直接不考虑这种机器人,直接通过调节参数,我们依然保持住了全国第一名。

决赛

决赛引入了大模型问答和多队同场景对抗,并加大了地图长宽。在练习赛初期,我们一直都在尝试优化大模型问答能力,期望获得最佳响应速度。在大模型问答模块基本确定之后,我们才开始着手修改代码。决赛过程中遇到的一个很严重的问题是由于地图扩大,我们复赛的代码初始化和船的寻路会直接超时,在对抗的场景下,掉帧对机器人和船损失都是特别大的,我们很大一部分时间在优化寻路算法。最后我们最终的代码是在复赛的基础上优化了寻路算法,加速了机器人的决策函数运行速度(通过一些剪枝手段),并增加了机器人和轮船避让其他人的策略,微调了机器人和轮船购买策略,并增加了一些参数用来调节机器人和轮船的避让博弈。

在决赛正式赛期间,赛题新增了一种轮船,价格只有普通轮船的2倍左右,但是载货量是4倍,在看到赛题的第一时间,我们认为,如果大家一起合作,那么购买这种轮船,整体赚取的总资金应该是更高的,因此我们还是尝试修改代码采用这种轮船。修改完提交上去,看回放才知道,尽管我们想跟其他队伍合作,但是其他队伍不配合,所以我们其实也只能选择原来的船去争抢泊位,在修改回原来的轮船之后,通过不断增大机器人和轮船的购买数量(通过调节购买因子),我们就一直保持第一名的排名不动,最后也很幸运的在最后一次PK中获得了总冠军。

2.整体方案

此处我们先介绍我们的整体流程,和一些我们的定义,然后按照初赛、复赛、决赛的代码修改点来详细介绍具体的思路(因为每一次改赛题,修改点都比较多),如果是没介绍的部分,就是沿用了初赛或者复赛的思路。

(1)整体流程和一些定义

我们的程序每一帧都做以下几件事:

1.机器人行动

  1.1.机器人决策

  1.2.机器人寻路和避让

2.轮船行动

  2.1.轮船决策

  2.2.轮船寻路和避让

3.机器人和轮船购买决策

初赛只需要考虑1(包含1.1、1.2)和2.1,复赛和决赛需要考虑1、2、3。

接下来给出一些我们自己的特殊的定义:

1.工作台(Workbench):指物品

2.机器人买(决策):机器人选择去某个物品处取(拣)货

3.机器人卖(决策):机器人选择去某个泊位卸货

4.轮船买(决策):轮船选择去某个泊位装货

5.轮船卖(决策):轮船选择去某个交货点出售货物

6.机器人和轮船购买:指购买机器人和轮船

(2)初赛思路

初赛由于只需要考虑机器人的控制和轮船的决策,所以优化机器人和轮船决策是得分的关键。

机器人决策

我们的机器人决策函数分为以下两部分:

1.对所有满货物的机器人分配一个卖决策

2.对所有机器人分配一个买决策

分配卖决策较为简单,我们直接选择最近的且有较大可能性卖出去(指轮船能拿到货物且能卖出去,此处判断较为简单,我们不展开讲)的泊位作为我们机器人的售卖泊位。

分配买决策是机器人决策的核心,我们为每一个机器人指定一个买家和一个卖家,具体地,我们在使用性价比=物品价值/买卖时间作为我们的估价函数的同时,也考虑了如下要素:

1.为了防止物品消失导致的价值损失,我们把物品消失时间当作一定的价值,让机器人尽量先找快消失的物品先去拿。

2.因为可能存在卖了之后离物品更近的机器人,我们给所有的机器人都分配了一个买决策。

3.因为中途切换目标可能带来损失,我们希望中途尽量不切换目标,因此我们增加了相同目标收益因子。

4.如果最后关头物品已经没法卖出去了(指轮船无法携带这个货物卖出去),我们直接设置为负收益,让机器人先找能卖出去的。

为了体现以上这些考虑,我们实现了以下代码所示的机器人决策购买函数:

1.png

2.png

机器人寻路和避让

机器人有两种状态,买(指去某个物品取货)和卖(指去某个泊位卸货)状态,这两种状态我们寻路和避让算法一致,只是目标点的不同。

机器人寻路算法较为简单,我们在初始化泊位和物品生成的时候,使用迪杰斯特拉算法计算保存起来任意点到泊位或者物品的回溯数组,寻路则直接回溯获得路径即可。

在机器人避让方面,先对机器人按照重要程度排序,如果检测到碰撞,我们最开始先尝试搜一条不撞的且距离等于最小距离的路径,如果能搜到,则直接切换路径。如果搜不到我们就继续正常走,直到下一帧撞了,才启动避让,具体策略是选择四个方向的下一个点和机器人本身所在位置作为候选点,选择最优的能避让对面的点作为下一个目标,具体做法是先计算点到目标距离,如果这个点在别的机器人路径上,则距离加2,选择距离最小的点作为最优点,如果没一个点能避让对面,则提高优先级,重新排序,并重新启动避让。

初赛轮船决策

我们的轮船决策函数也分为以下两部分:

1.对所有满货物或者剩余时间只够勉强卖货的轮船分配一个卖决策

2.对所有轮船分配一个买决策

分配卖决策较为简单,我们直接选择最近交货点作为我们轮船的货物出售点。

分配买决策是轮船决策的核心,我们为每一个轮船指定一个买家和一个卖家,由于初赛轮船没到泊位中途切换目标会重新计算时间,所以中途切换目标损失会很高,所以初赛我们的轮船决策保证中途一定不能切换目标。在决策之前,我们先初始化泊位货物数量数组,初始化等于泊位上的货物数量,当我们决策完一次时(一次只决策一艘轮船,与机器人一样),我们直接把泊位上的货物数量减去目前决策的船需要的货物数量,再进行下一次的决策。

我们的做法是按照把轮船进行分类,分别决策,具体如下:

1.途中的(前往交货点或者前往泊位途中的),先给予他们决策,选择保持原来目标不动。

2.没有买目标的(只有在交货点才会没有买目标),第二个给予决策,我们直接选择泊位剩余货物最多的泊位作为目标。

3.在泊位上的,细分为两种,第一种泊位上还存在货物,我们直接保持目标不变,如果不存在货物,我们预测等待装满需要时间,或者切换其他泊位装满需要时间,选择一个最快装满的泊位切换过去。

(3)复赛思路

复赛增加了机器人和轮船的购买机制,以及需要自己控制轮船的寻路和避让。此时得分的一个关键因素就成了如何高效地购买机器人和轮船。我们主要修改了轮船的决策,增加了轮船寻路和避让,增加了机器人和船的购买决策函数。

复赛轮船决策

由于复赛轮船没到目标不会重新计算时间,因此我们可以接受中途轮船切换目标,因此复赛的轮船买决策需要做一些改动。在泊位上的轮船且泊位上还有货物我们优先保持决策不变。对其他轮船,我们与机器人决策一样,直接用性价比作为我们的估价函数(泊位上的数量/轮船买卖时间),也增加一个相同目标收益因子。

轮船寻路和避让

轮船也有两种状态,买(指去某个泊位取货)和卖(指去某个交货点出售)状态,这两种状态我们寻路和避让算法一致,只是目标点的不同。

轮船寻路算法也较为简单,我们在初始化泊位和交货点的时候,使用迪杰斯特拉算法计算保存起来任意点到泊位或者交货点的回溯数组,寻路则直接回溯获得路径即可。有个需要注意的地方是如果某个泊位上有船了,我们会直接让轮船直接移动到泊位核心点处等待(通过广度优先搜索寻路),而不是搜到最近的靠泊区点就直接发送berth指令(因为一定发送失败)。

轮船避让方面,如果检测到碰撞,我们也先进行尝试搜一条不撞且等于最小距离的路径,搜得到,我们切换路径。如果我们搜不到,保持原来的路径,直到达到我们的检测阈值(10帧之内撞了),则启动局部避让算法,让低优先级船直接选择不在另外的船的预测路径上(每一艘只预测10帧)的且离目前船最近的25个点作为候选点,选择一个最优的点去移动过去进行避让,具体做法是目前移动距离+移动后的点到目标距离/2,选择最小的。为了防止极端情况,我们考虑了如果移动实在让不开,我们会发送dept指令让低优先级船去直接避让。

复赛轮船避让.gif

避让效果

机器人和轮船购买决策

在机器人和轮船购买方面,我们直接选择静态购买和动态购买相结合的方式。

1.设立最小机器人和轮船个数参数,用来静态购买。具体做法是只要机器人和轮船没到购买个数,我们一直购买,先买够机器人,再买够轮船。

2.设立购买机器人和轮船因子,用来动态购买。具体做法是从当前机器人获得的价值预估未来机器人能获得的价值,如果获得的价值大于购买机器人因子乘以机器人价格,则买一个机器人,轮船就预测目前泊位上的货和机器人未来卸的货能否被全部装走,如果不能装走,则看剩余的价值能否大于购买轮船因子乘以轮船价格,如果大于,则购买一艘轮船。

最后,在选择具体购买点方面,我们直接把购买点当作一次机器人或者轮船决策(机器人或者轮船位置在购买点的决策)。

为体现以上这些考虑,我们实现了以下代码所示的购买函数:

3.png

4.png

(4)决赛思路

决赛修改点主要是地图扩大,增加了大模型辅助问答和多队对抗机制。其中很重要的考察点其实是算法的性能,因为场上生成的货物非常多,很容易导致算法超内存或者超时。我们此时主要优化了机器人的决策函数、轮船的寻路函数,增加了避让其他选手的机器人和轮船的避让函数,并增加了大模型调用模块。

机器人决策函数优化

决赛整体采用初复赛的机器人决策,在复赛的基础上,我们增加了如下考虑:

1.剪枝策略,由于场上货物太多,我们先对货物价值排序,如果此时决策时间超过4ms,则我们只看前1/4的货物去决策,如果某些货物的最大收益已经小于当前最优收益了,我们直接停止,跳出循环。

2.答题状态特殊处理,因为决赛多了个答题状态,所以对初复赛的决策函数做了微调,答题状态的先决策。

3.取消了物品消失价值(因为低价值物品太多,拿不完,消失了也没事),降低了相同目标因子为0.5(初复赛一般为2,因为决赛中途切换能尽早抢到高价值货物)。

此外我们不考虑只把货物卖给有自己船的泊位,因为我们认为,大家合作才能赚取整体的更高利润。

实现以上这些考虑的具体代码如下:

5.png

6.png

轮船的寻路函数优化

因为复赛我们采用的轮船寻路是广度优先搜索,到了决赛地图扩大寻路会比较耗时,我们采用有序字典(map)加栈(stack)来优化轮船的广度优先搜索寻路,具体做法是有序字典用最小深度作为键,用栈作为值。

优化完毕的整体代码如下,注:DIR长度为8,只有前4个有用。

7.png

8.png

避让其他选手的机器人和船

避让其实是一种博弈,我们乐观地认为碰到会动的机器人和船都会避让我们(如果对面不避让,我们保证对面至少吃亏1帧),所以我们考虑如果我们撞到的机器人或者船能动,我们暂时不避让,如果他不能动,我们撞到之前直接让开他。

我们的具体做法如下:

1.如果我们的机器人2帧之内不动(或者下一个位置有超过5帧不动的机器人),则锁死下一个位置,重新搜一条不撞的路径。

2.如果我们的轮船3帧之内不动(或者下一个位置有超过6帧不动的轮船),则锁死下一个位置,也搜一条不撞的路径。

决赛避让其他机器人.gif

机器人遇到移动机器人的避让

大模型问答模块

大模型方面我们能做的只有以下两件事:

1.设置大模型解码参数

2.设置提示词

在解码参数设置方面,我们只追求大模型的最快响应速度,因为我们认为就算我们答错,其他队伍大概率也答错,我们也不亏,因此我们的大模型解码策略应该为贪心,所以设置top_k:1参数。

在提示词设置方面,我们增加了个后缀英文提示词用来减少大模型输出单词数量,在正式赛时可以看出我们的大模型响应速度还是排名比较靠前的(这个也是一个比较遗憾的地方,我们没有获得最快响应速度,比最快队伍的响应速度慢了大约1/2)。

我们这个模块的整体策略是开一个后台线程,不断读取问题,发送问题,如果没有问题,我们就让线程休眠1ms,放弃CPU,有问题就不断发送问题,获得回答,需要注意的一个点是我们因为建立连接大约需要0.5s,第一次获得响应会比较耗时,因此我们在初始化的时候直接发送了个问题给大模型以此建立连接,后面复用这个连接,响应速度就正常了。

实现大模型问答模块的关键代码如下:

9.png

其他

决赛对物品的迪杰斯特拉算法也做了个搜索深度的限制,贵重物品搜索300深度,低价值物品只搜索100深度(因为搜索是在主线程,为了防止超时),对机器人和轮船购买策略做了细微的改动,机器人只关心自己能拿的价值,场上其他选手的机器人拿的价值不在考虑范围内,轮船只关注自己的机器人能拿的货,只买够自己机器人运货的船,整体目标是不希望跟别人抢,一起获取更高的利润。

3.总结

此次软挑,我们队并非一帆风顺,在比赛过程中,我们面对了各种困难和挑战,但我们坚持不懈地寻找解决方案,在比赛中,我深入研究了各种算法和数据结构,学会了如何选择适当的算法和数据结构,以提高代码的效率和性能。这个过程同时也锻炼了我的毅力和决心,让我学会了在压力下保持冷静和专注。同时,通过与其他优秀的参赛队伍接触和交流,我深刻地认识到自己的不足之处,也看到了其他人的优秀之处。这激励着我要不断学习和提升自己,保持对知识的渴望和探索精神。

最后,我要衷心感谢我的母校为我提供的优质的教育环境,以及家人、朋友以及师兄师姐们给予我的鼓励和关心。感谢华为提供的这个宝贵的机会和平台,让我能够参与这个比赛,并且有幸能够与一些专家和行业大佬进行交流,这对我的职业发展产生了深远的影响。

「免责声明」:以上页面展示信息由第三方发布,目的在于传播更多信息,与本网站立场无关。我们不保证该信息(包括但不限于文字、数据及图表)全部或者部分内容的准确性、真实性、完整性、有效性、及时性、原创性等。相关信息并未经过本网站证实,不对您构成任何投资建议,据此操作,风险自担,以上网页呈现的图片均为自发上传,如发生图片侵权行为与我们无关,如有请直接微信联系g1002718958。


CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
微博关注
【免责声明:CSDN本栏目发布信息,目的在于传播更多信息,丰富网络文化,稿件仅代表作者个人观点,与CSDN无关。其原创性以及文中陈述文字和文字内容未经本网证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本网不做任何保证或者承诺,请读者仅作参考,并请自行核实相关内容。您若对该稿件有任何怀疑或质疑,请立即与CSDN联系,我们将迅速给您回应并做处理。】