记一次逗逼的codecraft算法大赛的参赛经历

为情怀而战,开撸!

codecraft是菊厂举办的有关图论的算法挑战赛,一次比赛一道题NP-Hard的问题,比的是谁设计出来的算法求解出来的结果最优,主要目标是在既定的地理图上进行服务器的部署和流量的配置,在满足需求的前提下尽量省钱。

我本来不打算参加这个比赛的,第一,我代码写的实在太烂,第二,数学功底实在太差,做科研凭直觉,做论证凭的是一套成熟的民科理论,所以感觉我和这种又考建模又考程序的比赛实在搭不着边。(哦对了,比赛是用C草或者爪哇,我平时调机械臂用的是Pascal语言,各种业余,不言自明)

后来在周围同学的鼓励下(后来的队友的坑蒙拐骗下),以及自己本身对科技学术比赛的热爱(TOP奖有20W),开始了一段戏剧性的历程。

蛋疼的开始

这个比赛比较人性化,官方直接提供SDK,不用自己写编译文件,直接提供SHELL脚本一站式编译打包,主函数文件读写都搞好了,自己只要在功能函数实现算法就OK。

我一开始叫他们别急着写数据结构,没卵用,先把问题想清楚,经过了维持1一天一次的晚会讨论,一开始定调很高,大家都觉得不能 ,觉得这个整数规划问题一定要建模,然后转化为经典的最优化问题,自己写个高性能的优化算法,看各种次梯度啦,拉格朗日松弛,绝不用LOW-B的搜索。

然而并没有什么卵用,看了很多选址问题的文章依然不能解决我们的问题,最后我也只能妥协,好吧那先写数据结构,把读进来的字符串数据规范化,然后服务器直连传上去试试看,然后重点就来了。

队长诞生记

他们说我去年参加过,所以以前写的代码还能用用,自己想想也有道理,嗯,那就写完这个就不写了~
然后就是~我写的类他们看不懂,一开始好好解释一波,大家还是磨合得很愉快的,但后来我渐渐发现了自己写的东西很多漏洞,一边用要一边补~就这样,我写的东西只有我自己能用,循循善诱地把自己带进了坑,后面的程序就都变成我写了,自然而然地成为了队长。

误入歧途

(队友):我觉的这个还是个路径规划的问题,从起点到终点一条条路搜索。
(我):这个要考虑到流量合理分配和宽带上限,需要一个机制和框架,单纯搜路没屌用。
(队友):那就把上限考虑进去,用完就用下一条。
(我):不要把问题想的太简单,这样结果会受到搜顺序影响,前后耦合太大,无法从全局考虑。
(队友):那怎么搞。
(我):我已经想好了,在假定服务器位置确定的情况下,每个消费节点对所有服务器用最大流SAP算法,基于GAP优化和Dis启发的SAP势必能让程序快得飞起,再用增广路径作为流量路线,完美!
(队友):那超出流量限定怎么办。
(我):我自己搞个流量局部再调整机制,局部流量调整按次优方向进行再分配~绝对靠谱!
[这特么是我做的最愚蠢的决定,硬生生把刷新了SAP算法的下限,跑一次解竟然把SAP跑了N(消费节点数)次,创造了原本不需要考虑的问题,还想方设法解决这个问题-_-]

越陷越深,不能自拔

就这样按照错误的思维,硬生生把SAP和超流量调整边的策略写完了,在完全没有发现问题的情况下还一副稍有成就的样子,可是~,经过用例测试虽然可以有解,但是解的质量都不高,并且求解时间慢的不可饶恕,高级用例竟然慢到到了一秒一步的地步,当时,我还自认为这已经是求解速度瓶颈,并没有多加理会,只是想着怎么优化求解方法。
我当时之所以用SAP而没有用最小费用流是因为总感觉最消费用流貌似由于最小费用的条件约束会导致最后可选增广路径的减少和求解速度的减慢。为此,我还把SPFA也就是最小费用流的一种方法实现了一遍,套到我自己的求解框架下(-_-),然后就是发现不管从速度还是解的质量貌似都没有很大的提升~(最小费用流的提出者要是知道估计会吐血)

于是乎转战遗传算法来优化服务器部署策略,其实严格来说我特么当时写的根本不是遗传算法,只写了一个种群,然后保留前N个优解,在种内进行交叉~交叉规则现在想想还算靠谱,让两组解向量相同的元素留下,不同的元素二分之一概率的留下,然后进行把结果用于服务器部署,不能满足的消费节点直接直连!!!(估计当初整个遗传算法起作用的就只有这个操作了~)

嗯!有效果,可是对于高级用力根本有心无力,求解速度太慢,还没收敛90秒的程序限制时间就结束了!!!

为了提高收敛速度,创造性地提出了种内“群交”算法,让种群内N个样本同时交配,其实就是元素的相同度大的留下的概率大,反之小,嗯~收敛速度貌似快了,可是收敛的解很“辣鸡”,哎,拍脑袋出来的东西果然没什么好结果。到此,已感觉黔驴技穷~

勉强走上正轨~

就这样一顿瞎搞,离初赛结束就剩下3天了~第一次发现自己的脑子这么不好使,支撑我坚持下去的信条就是,我始终相信答案的客观存在,而且就在眼前,它一直在等你去发现他,可是我特么感觉就是和别人做得不是同一道题,为什么我遇到的问题别人没遇到过???

(队友):你是不是考虑把最小流合并一下?
(我):??????

不懂,先看一波《人民的名义》平抚一下心情,结果心情平抚不了,这一看,心情波涛汹涌,一看就是6集,看到陈岩石讲课回顾历史那段,突然脑子背后闪过了一条射线,茅塞顿开!我最最小费用流用错了!!!应该用“多源多汇”的方式!把消费节点用一个网络节点连接起来,然后把边的流量限制设置为流量需求就好了嘛,而且也不用担心流量超载的问题,要是实在不够,直连就好,干!干!干!

当然《人民的名义》也是要继续看的,一直看到第7集,第8集,第9集,第9集的时候!!!把解法写好了,试试本地用例!!!速度飞起,解一次的速度是原来的N倍(消费节点的个数),高级用例直接快了300倍!!!感觉终于上车了~

神转折,效果拔群!

离初赛结束还剩5个小时!
现在的排名分分钟跌出榜单,还好,有队友一直在那调参,令我很感动,他把输出的cost和输入的规模以及种群数做一个拟合,以便每次对应一种规模能用用合适的规模去找到最好的解,以至于我们还能苟延残喘。

离初赛结束还剩3个小时,实验室有人在讨论《人民的名义》的剧情,我凑了过去,把思绪从题目中释放出来,好歹放松一下,经过了一波剧透和热烈的讨论,我想剩下的几十集我都不用看了,节省了一大波时间,整个人神清气爽,嗯,顺便去打点水喝。

回到座位已经离初赛结束只剩下1个小时了,当然也不抱有希望了,败北得心安理得,看到不停下滑的排名,就像看着“不进则退”的人生。

剩下40分钟,我打开了《人民的名义》的剧透分析,突然一跳出了个装修公司的广告-“我们永远把客户的需求放在第一位”

此时我脑海突然灵光一现,一束光从我背后穿了过去!

(我):“soga,我可以这样的,初始服务器分配应该按需分配,给每个备选服务器的位置根据需求设置被选中的概率,通过排序,需求越大的越可能被选中,然后产生随机数进行采样就行!!!”

全身突然细胞突然充满ATP!,奋笔疾书!

离初赛还有10分钟!程序写完!,立马用本地测试用例试了一下,OMG!!!效果拔群,初始的种群质量不知道比原来好了多少倍,结果比原来有了质的提升!!!赶紧,把代码打包发了上去,OK,赶在了12点前提交了,现在坐等结果!!!

人算不如天算

判卷系统判卷要一段时间,此时已经12点半了,实验室只剩我和队友两人,跌宕起伏的情绪让实验室翻滚着饥饿的味道。
(我):真是千钧一发,没想到临门一脚还能峰回路转,最后的优化真的神来之笔!
(队友):你应该早点想到,刚才要是不去讨论电视剧,现在说不定还有时间调参数,进32不是梦。
(我):哎,有些事情不能勉强,有些问题硬想是想不到的,要靠一些漫不经心的灵感。
(队友):判卷结果应该出来了,来见证下奇迹。。。。。。卧槽。
(我):怎么回事?零分!!!WTF?
(队友):判卷系统解压失败啊。

(我):HI可能,我用官方的bash打包的!!!
(队友):你命错名字了啊,后缀是.tar.gz,你把tar当成文件名重名的。
(我):我TM,重命名的时候系统自动选中的啊,嚓,真坑,windows自动把最后一个点之前的字符串当文件名重命了。
(队友):你重命名干嘛?
(我):我想纪念下这一难忘的时刻。
(队友):-_-。

结语

虽然结果惨淡收场,但还是学到不少东西的(做比认真点,不要搞事情)。


所有原创文章都会在第一时间发布到以下公众号,欢迎关注!

你可能感兴趣的:(学术科研)