目录

一.写在前面的话

二、语言选择

三、判题器实现

四、回溯解死锁

四、发车时间设计

五、寻路设计

六、写在最后的话


一.写在前面的话

第一次参加软件精英挑战赛,复赛最后打了第六名,队名是行车不规范亲人两行泪,我们上台时候,主持人都说这队名真应景啊…就差两名就可以进决赛了,但是不得不说前面的大佬真的是太强了,把我们甩的贼老远。不过也没什么遗憾,复赛练习赛时候也差不多是5-8名左右,所以正式比赛就想着要保住前十,别拿第五(感谢第五老铁抗雷…),最好第六,也算是如愿以偿了。

代码和数据在git上面:https://github.com/zhangbaodan/2019HUAWEI

主要分享下解死锁思路以及寻路那边的一些特征提取。如果您觉得有帮助的话,记得git上面点个小星星哇~

再放张队名图片(美工小姐姐真的是太用心了)

二、语言选择

和往年一样,今年也开放了三种语言c++,java,python。最开始接触这个题时候,感觉用不到机器学习的东西(我们太菜,想了半天没想到,大佬估计用得到)。所以就把python给pass掉了,毕竟这玩意运行起来太慢了,后面也有很多队吃了这个语言的亏。c++写起来太复杂(主要是我c++写的太菜,我的c++ = c + stl),所以把c++也pass掉了。而且感觉这个比赛car,road,cross刚好三个类,java写起来会比较顺手,而且很多封装的类写起来也比较方便,运行时间上面也和c++差距不是很大,所以最后选择了java(西北复赛32个队里面,只有三个java,四个pyhon,看来c++大佬是真的多)。

三、判题器实现

周五放的比赛,晚上时候经过讨论,决定先把判题器撸出来,做出这个决定着实不容易,光规则就有19页,能不能撸出来真的不好说,但还是决定赌一把(真的感谢当初这个决定)。那么,对于计算机来说,每次我只能更新一辆车,哪以什么样的方式把所有车都更新完呢?那时候,官方还没有更新任何有关判题器逻辑的东西,所以都只能自己想。我们决定按ID顺序遍历所有的车辆,对于某一个车辆,如果有车辆影响到它的更新,那么就一直深度遍历更新下去(官方采用按cross和road方式遍历,事实证明他们的思路更清晰,实现起来也更容易),这是我们一开始写的逻辑图:                                                                                                                                

最开始打算按照车辆去遍历,如果遇到影响当前车辆更新的车辆,那么就一直DFS更新下去,看上去漏洞百出,和官方给出的逻辑完全不一样,但也就还是按着这玩意撸了。差不多撸了两三天,一个看上去能用,实际完全用不了的判题器就横空出世了。然后路径规划那块搞了搞,算是能用了。过了一周以后,官方可以线上提交代码了,第一天晚上提交时候各种死锁。把发车时间打的很散以后终于跑通了,两张图跑了80000左右…

实现这玩意着实不容易,尤其最开始官方啥都没说的时候,每天就是一边撸,一边看官方的论坛回复,看看有没有自己没有注意到的问题,而且是一边看官方回复,一边怀疑官方回复是不是错的,因为在有点地方,我们按照他的逻辑改,反而更不准了,最后索性都不看论坛了(事实证明,永远不要怀疑官方...)。

很遗憾的是,官方在初赛后期几乎完全公布了判题器逻辑时候,由于那时候我们判题器逻辑已经定型了(不太准),看了他们的逻辑,感觉差不多,就没有完全按照他们的逻辑去改。这一下子偷懒,直接导致我们一个星期死在判题器上面。后面实在找不到BUG了,就痛定思痛,把直接写的逻辑全删,完全按照官方的逻辑去写(连命名都和官方一模一样),结果很神奇的就一致了。

然而,我们一直偷了一个懒。官方之前一直强调cross的ID不保证连续,直到初赛比赛的早上,我才火急火燎的改成不连续读取,但是判题器按照路口ID升序遍历那块忘记改了,导致判题器不准。再加上我们回溯方案很耗时间,初赛练习赛时候没有表现出来,正式比赛时候,数据量一上去,我们立马就超时了。只能换回一个星期以前的思路(没有回溯),胡乱调参,还好苟进复赛了(24/32)。

复赛时候,由于增加了优先级车辆以及预置车辆,所以判题器需要大改。官方索性放出了完整的逻辑导图(这逻辑图是真的清晰,什么时候才能写出这么优雅的逻辑)。有了初赛踩坑经历,这次我们决定一模一样复现他的逻辑(名字都一样)。差不多在复赛前一个星期,线上线下完全一致了(总时间后几位不一致,这是因为四舍五入的关系,所以没太在意),提交上去一页都是提交成功(绿色)的感觉是真的爽。

总之,对于我们队来说,复现别人的东西也是一个不小的难题。一定要坚信官方是对的(就像代码给你报bug,绝对不能怀疑编辑器,一定要有对不起,都是我的错,我一定改的态度一样),坚持弄下去,一定能搞出来!

四、回溯解死锁

当发生死锁的时候,我们可以获得死锁对应的车辆以及对应的路和路口。如果我们能够事先对这些车辆以及路口做一定的管控的话,死锁就不会发生了。

最简单的方法是,当发生死锁后,让时光倒流,回到过去,然后做一定的调整,也就是回溯解锁的办法。首先,我们来说下如何回溯,不管采用何种回溯解锁思路,前提条件是能回的去。比如在第100秒时候发生死锁,如何回到90秒?一种很暴力的思想是重头仿真到90秒,这种方案肯定用不了,太耗时了。我们在初赛时候,采用的方案是,对于每一秒,我们都记录下该时刻对应的所有仿真信息。如果想回到90秒,只要读取对应实现记录的信息,做一个替换就好了。(这里在工程上需要注意的是深拷贝和浅拷贝的问题,我们一定要做深拷贝,浅拷贝会导致地址共用,会出很多BUG)。

然而...每一次记录都需要话很大的时间(如果车辆数很多的话,代价更大),这也直接导致我们初赛代码超时。复赛时候,我们采用每隔10秒记录一次信息,这样整个耗时相比于原来就小了10倍,而且这样的操作对回溯并没有产生很大的影响,发生死锁后,我们只需要退回到最近的记录的时间片就可以了。

回溯后,一般采用的是回溯改路或者回溯不发车的思想,我们采用的是后者,比如在第100秒时候发生死锁,记录发生死锁车辆以及发生死锁路口(以及路口周围的路口)。然后回到90秒(有一个类用于保存对应时间片的所有仿真信息,将90秒到100秒记为forbidTime。期间有三个策略来尽量保证再次回到100秒时候,不会发生死锁:

1、100秒发生死锁的车辆不允许在这期间发车(如果它原来实在这期间发车话);

2、死锁路口以及周围路口不允许发车;

3、全图允许存在的车辆数按百分比减小,因为我们有个很大的参数是控制当前地图下最大允许存在的车辆数,把这个参数减小以后,也会降低死锁可能性。

当然,在这三种策略下也不能百分百保证第100秒时候不发生死锁。我们的策略是如果不行,就再往会倒10秒,回到80秒,如果还不行就继续往回倒...,当然,往回倒多少次取决于当前最大记录了多少时间片信息。往回倒的时间片越多,在第100秒时候,整个车辆数就越小,发生死锁可能性就越小。

四、发车时间设计

有一个很重要的点是控制车辆的发车时间。我目前知道的两种普遍的做法是:方案1.每隔几秒发一波车;方案2.控制全图车辆总数,如果当前地图上车辆总数小于这个阈值,就立马发一些车作为补充。我们初赛采用的是方案1,复赛采用的是方案2。

方案1:每隔几秒钟就发一波车,这种策略可以使得等到下一次发车时间到的时候,上一次发的车很大一部分就已经到达终点了。这样的发车策略,在一定程度上预防了死锁。这种策略下有如下若干问题:

       同一个发车批次下,应该发哪些车。有些做法是让同一个发车批次下,车辆的始发地尽可能的分散。还有一种做法是,让车辆的速度尽可能一致。在初赛时候,我们采用了后者,因为同样速度下,车与车之间的空隙会尽可能的小。这样道路容纳量会比较大。那么,先发速度大的还是小的?我发现很多人的做法是先发速度大的,他们认为速度大的会尽快到达终点,不会对后面速度小的车辆产生过大的影响。但是,不晓得为啥,我们模型里面先发速度小的结果会比较好。而且,我认为先发大或者小结果应该是一样的。

       每次应该发多少车?如果同一个发车批次下,车辆速度都尽可能一致的话,我认为速度小的时候,可以多发一些车,速度大的时候,可以少发一些车。因为速度越大,越容易死锁。如果速度是16的话,假设其要跨越路口(当前在路的最前面),那么下一条路的可以进入的车道中,如果从后往后数16个格子内存在一个等待车辆,那么它就肯定是等待状态了。而如果速度是4的话,只看4个格子。所以速度越大,越容易死锁,地图容纳总数就越小。

       发车间隔是多少?发车间隔其实也控制这地图车辆总数,因此,速度大的时候发车间隔大一点,速度小的时候,发车间隔小一点会比较好。

方案2是我们复赛采用的方案,首先,按速度发车的思想没有变。我们不去控制发车间隔以及发车量。而是直接去控制地图上总车辆数,这样两个参数简化为一个参数,而且控制的效果更好。在不同速度下,发车的总量也是不一样的(和方案1一样)。速度越大,发车总量越小。

在复赛中,对于优先级车辆,能发就发,不按照速度来发,我们会控制一个优先级车辆发车时候的总地图容纳量。对于普通车辆,会控制一个允许普通车辆加入的最早时间。在最早加入时间到了以后,按照速度有小到大依次发车,不同速度下设置不同的车辆总数。

五、寻路设计

寻路无非有两种寻路,一种是没有仿真之前,就事先规划好他的路,还有一种是,等到它真正要出发的时候,在去寻路。我们采用的是后者,比如在仿真到第100秒时候,有一辆车要出发,我们就把第100秒的地图以及那辆车扔给寻路算法,返回一条路径来。这样会比事先规定路线要准确一些。

寻路主要采用的是dijkstra算法。其核心是对于路的权重设定。我们在寻路这一块做的比较烂,很大一部分精力都放在判题器和解锁以及发车上面了,在我们很烂的寻路模型中一共有如下几个参数:

        1.行驶完这条路所需要的时间

这个参数应该是大家都能想到的一个参数,但在我们模型中,因为是分速度调参的,在前面几个速度中,这个参数的权重并不是很大,如果很大的话,车辆很容易立马发生死锁。当然,我们会在最后两三个速度下,把这个权重调的大一点,因为后面已经没有多少车加入了,所以尽可能让他早走完比较好。

       2.当前车道拥挤程度

道路拥挤程度通过(道路总容纳量 – 道路可加入量)/道路总容纳量计算得到,这里我们计算的不是道路已有车辆数,而是道路可加入量,这可能和其他队伍的计算方式不太一样。这个参数对应权重比较大,因为我们希望车辆能够均匀的分散开来。即使这样做会绕比较远的路,但我们认为这样也是可以接受的。

       3. 速度差异

我们希望车和道路之间的速度尽可能接近,如果车速高于路速的话,对于车来说本身是个损失;如果路速高于车速的话,会导致该车后面的车有可能损失速度;如果车速等于路速的话,该路上车的速度都一直,速度损失将会降到最小。

       4. 已经选择确尚未到达该路的普通车辆数

这个对应权重设的比较小,也不晓得有没有用~

       5. 已经选择却尚未到达该路的优先级车辆数

这个权重就设的比较大了,因为优先级车辆本身计算权重就比较大,我们尽可能让非优先级车辆不去选择优先级车辆已经选择的路。这样即使在最开始优先级车辆行驶中,我们加入一些非优先级车辆,也不会对优先级车辆运行的总时间产生过大的影响(如果设置的无穷大的话,优先级车辆总时间只可能降,不会升)。

关于动态改路的问题,首先,做动态改路肯定是能够降低总时间的,但是,我们寻路模型可能太烂了,改了反而不如不改…


六、写在最后的话

这次比赛称为华为软挑有史以来最变态的一次,代码量要求真的是很大。通过这次比赛,也使得自己对代码风格和代码管理这一块有了很大的提升。感觉我们失利的主要原因是在寻路那一块做的很烂,尤其是在看了别人开源的代码以后。总之,长路漫漫,来年再战!

2019华为软件精英挑战赛分享相关推荐

  1. 2019华为软件精英挑战赛比赛经验分享(初赛,复赛,决赛)

    比赛成果: 初赛(700+):西北赛区第3. 复赛(32):西北赛区第3.(华为手机v20,华为面试绿卡,西北赛区二等奖,小礼物若干) 决赛(32):全国16强,具体排名13.(没有奖金,纪念品若干, ...

  2. 2019华为软件精英挑战赛参赛心得

    1. 说在开头: 我们是来自江山赛区的[我是一条大锦鲤大锦鲤我们不会死锁呀死锁呀]队伍,这个队名不止一次被我队友调侃为沙吊/哈哈哈,开头我不得不舔一波华为公司,华为公司对这个比赛准备的真的很好,很贴心 ...

  3. 2019华为软件精英挑战赛赛后总结

    先摆上最后成绩:西北赛区复赛18名 队名:心有多大路就有多宽 现在离比赛结束已经快一个月过去了,成绩不佳,老师那边也有活要忙,赛后总结就耽搁下来了.最近闲下来,所以写一写总结,当作是个留念吧. 队伍名 ...

  4. 2019华为软件精英挑战赛

    大致思路: 初步考虑是,不考虑拥堵,用Dijkstra算每辆车的最短路径,然后直接按照规则跑! 先这么着写一个出来,之后再加入拥堵的因素,并根据即时性,综合此时的路况拥堵和路径长短,让每辆车在行进到每 ...

  5. 2019华为软件精英挑战赛总结(附代码)

    初赛江山赛区十六名然后时间冲突复赛放弃了.(放弃了免费旅游qaq!) 本来一开始就想写一个总结 因为之前搜dalao们的博客的时候很少有江山赛区的总结 复赛结束也有一段时间了 这段时间acm比赛有点多 ...

  6. 2021华为软件精英挑战赛总结分享

    2021华为软件精英挑战赛总结分享 随着大赛的结束,自己的2021软挑也落下了帷幕,很幸运在自己学业生涯的最后几个月能够再参加一次华为软挑,虽然成绩不是特别好,但已经满足了.这是自己第二次参加华为的比 ...

  7. 2023华为软件精英挑战赛,探寻软件人才与科技创新的最优解

    作者 | 曾响铃 文 | 响铃说 今天,软件行业正呈现出江河入海一般的大汇流趋势. 一方面是技术的汇流,诸如人工智能等前沿技术与软件行业的深度融合,正全面颠覆软件产品的开发模式和服务逻辑. 另一方面则 ...

  8. 2018华为软件精英挑战赛

    今天12点,历时一个多月的2018华为软件精英挑战赛训练赛结束了,最后分数215.597(总分300),很遗憾,前64都没能进,不过还算尽力坚持到最后. 3月初,华为软赛开始一周后,看到师兄他们在弄, ...

  9. 2022年华为软件精英挑战赛区域初赛解读(基于数学规划模型附代码)

    0 写在前面的 本文是对2022年华为软件精英挑战赛(普朗克计划)区域初赛的一个解读.首先说明的是本文的算法无法直接拿来参赛的,因为区域初赛的要求是不能调用其它的算法包,python的话只能用nump ...

最新文章

  1. Debian/Ubuntu/Centos下编译安装RocksDB
  2. 初识、理解生成器模式
  3. [翻译]Feedback on the Go Challenge solutions
  4. Georgia and Bob(Poj 1704)Nim 博弈
  5. SentOS 7防火墙配置与端口增删改查的命令
  6. 来啊,一起造作啊!10月仍然还有十多场新品发布会...
  7. 找上海或深圳塑胶模具工作
  8. Springboot,log文件配置时,logging.file.name与logging.file
  9. Java中String的用法
  10. 在php中插入图片,php中怎么插入图片
  11. Linux命令行下播放音乐SOX
  12. 微信读书 iOS 性能优化总结
  13. 关于TypeScript开发的6个小技巧
  14. 基于java web的在线电影网_视频点播系统-计算机毕业设计
  15. winrar去掉烦人的广告 亲测有效
  16. 通用技术课件_技术设计的一般过程 | 高中通用技术优质课展示
  17. 为什么在抖音直播间打字别人看不见,所有抖音直播间看不见我说话
  18. oracle分类账设置,Oracle EBS R12 总帐和子分类账关系详解[转载]
  19. 计算机视觉、模式识别、图像处理领域的国际会议和会议排名
  20. 极客时间--数据结构与算法之美

热门文章

  1. 走技术线路的研究生如何发表论文?
  2. 【专题目录03】mmu/cache
  3. 国内量化交易平台盘点
  4. java pixelformat_Java PixelFormat.OPAQUE屬性代碼示例
  5. 《ANSYS Workbench 14有限元分析自学手册》——1.7 一个简单的分析实例
  6. 关于 URLLC场景下的 the Short Blocklength Regime
  7. 微信开发者工具上传时 包超出限制的问题
  8. BZOJ 2073: [POI2004]PRZ 状压动归
  9. Boyer-Moore 算法讲解
  10. 苹果公司对蓝牙免提AT指令的扩充