2019华为软件精英挑战赛分享
目录
一.写在前面的话
二、语言选择
三、判题器实现
四、回溯解死锁
四、发车时间设计
五、寻路设计
六、写在最后的话
一.写在前面的话
第一次参加软件精英挑战赛,复赛最后打了第六名,队名是行车不规范亲人两行泪,我们上台时候,主持人都说这队名真应景啊…就差两名就可以进决赛了,但是不得不说前面的大佬真的是太强了,把我们甩的贼老远。不过也没什么遗憾,复赛练习赛时候也差不多是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华为软件精英挑战赛分享相关推荐
- 2019华为软件精英挑战赛比赛经验分享(初赛,复赛,决赛)
比赛成果: 初赛(700+):西北赛区第3. 复赛(32):西北赛区第3.(华为手机v20,华为面试绿卡,西北赛区二等奖,小礼物若干) 决赛(32):全国16强,具体排名13.(没有奖金,纪念品若干, ...
- 2019华为软件精英挑战赛参赛心得
1. 说在开头: 我们是来自江山赛区的[我是一条大锦鲤大锦鲤我们不会死锁呀死锁呀]队伍,这个队名不止一次被我队友调侃为沙吊/哈哈哈,开头我不得不舔一波华为公司,华为公司对这个比赛准备的真的很好,很贴心 ...
- 2019华为软件精英挑战赛赛后总结
先摆上最后成绩:西北赛区复赛18名 队名:心有多大路就有多宽 现在离比赛结束已经快一个月过去了,成绩不佳,老师那边也有活要忙,赛后总结就耽搁下来了.最近闲下来,所以写一写总结,当作是个留念吧. 队伍名 ...
- 2019华为软件精英挑战赛
大致思路: 初步考虑是,不考虑拥堵,用Dijkstra算每辆车的最短路径,然后直接按照规则跑! 先这么着写一个出来,之后再加入拥堵的因素,并根据即时性,综合此时的路况拥堵和路径长短,让每辆车在行进到每 ...
- 2019华为软件精英挑战赛总结(附代码)
初赛江山赛区十六名然后时间冲突复赛放弃了.(放弃了免费旅游qaq!) 本来一开始就想写一个总结 因为之前搜dalao们的博客的时候很少有江山赛区的总结 复赛结束也有一段时间了 这段时间acm比赛有点多 ...
- 2021华为软件精英挑战赛总结分享
2021华为软件精英挑战赛总结分享 随着大赛的结束,自己的2021软挑也落下了帷幕,很幸运在自己学业生涯的最后几个月能够再参加一次华为软挑,虽然成绩不是特别好,但已经满足了.这是自己第二次参加华为的比 ...
- 2023华为软件精英挑战赛,探寻软件人才与科技创新的最优解
作者 | 曾响铃 文 | 响铃说 今天,软件行业正呈现出江河入海一般的大汇流趋势. 一方面是技术的汇流,诸如人工智能等前沿技术与软件行业的深度融合,正全面颠覆软件产品的开发模式和服务逻辑. 另一方面则 ...
- 2018华为软件精英挑战赛
今天12点,历时一个多月的2018华为软件精英挑战赛训练赛结束了,最后分数215.597(总分300),很遗憾,前64都没能进,不过还算尽力坚持到最后. 3月初,华为软赛开始一周后,看到师兄他们在弄, ...
- 2022年华为软件精英挑战赛区域初赛解读(基于数学规划模型附代码)
0 写在前面的 本文是对2022年华为软件精英挑战赛(普朗克计划)区域初赛的一个解读.首先说明的是本文的算法无法直接拿来参赛的,因为区域初赛的要求是不能调用其它的算法包,python的话只能用nump ...
最新文章
- Debian/Ubuntu/Centos下编译安装RocksDB
- 初识、理解生成器模式
- [翻译]Feedback on the Go Challenge solutions
- Georgia and Bob(Poj 1704)Nim 博弈
- SentOS 7防火墙配置与端口增删改查的命令
- 来啊,一起造作啊!10月仍然还有十多场新品发布会...
- 找上海或深圳塑胶模具工作
- Springboot,log文件配置时,logging.file.name与logging.file
- Java中String的用法
- 在php中插入图片,php中怎么插入图片
- Linux命令行下播放音乐SOX
- 微信读书 iOS 性能优化总结
- 关于TypeScript开发的6个小技巧
- 基于java web的在线电影网_视频点播系统-计算机毕业设计
- winrar去掉烦人的广告 亲测有效
- 通用技术课件_技术设计的一般过程 | 高中通用技术优质课展示
- 为什么在抖音直播间打字别人看不见,所有抖音直播间看不见我说话
- oracle分类账设置,Oracle EBS R12 总帐和子分类账关系详解[转载]
- 计算机视觉、模式识别、图像处理领域的国际会议和会议排名
- 极客时间--数据结构与算法之美
热门文章
- 走技术线路的研究生如何发表论文?
- 【专题目录03】mmu/cache
- 国内量化交易平台盘点
- java pixelformat_Java PixelFormat.OPAQUE屬性代碼示例
- 《ANSYS Workbench 14有限元分析自学手册》——1.7 一个简单的分析实例
- 关于 URLLC场景下的 the Short Blocklength Regime
- 微信开发者工具上传时 包超出限制的问题
- BZOJ 2073: [POI2004]PRZ 状压动归
- Boyer-Moore 算法讲解
- 苹果公司对蓝牙免提AT指令的扩充