2017HW軟件精英挑戰賽總結

引子

先解釋一下隊名rOtp。對於華爲軟件精英挑戰賽來說,我們已經算是老司機了,去年我們以隊名“寫bug小王紙與找bug小公舉”初次參賽,折戟總決賽的16進8環節,與獎金失之交臂。同組第二名在落後了整整一下午的情況下,在最後十分鐘提交了一份代碼,完成了絕殺,我們被打到第二,淘汰賽首輪就不幸對陣到了最終的季軍隊伍,最終鎩羽而歸。這次失敗經歷給我留下了沉重的打擊,我不服,明年我們還要來。rOtp的名字是隊長起的,借鑑了dota戰隊rOtk的命名思路,return of the prince,即王子歸來,看到隊名後我們一拍即合,幹!順便解釋一下我們的團隊口號,“身無綵鳳雙飛翼,心有靈犀一點通”,一句詩中包含了我倆女朋友的名字,真是天意啊233.

初賽

初賽的題目就不贅述了。我們將去年的失敗的遺憾全部轉化成了對今年比賽的重視,2號,比賽羣裏流露出了疑似今年的賽題,後經證實是網站GG的操作失誤,被手快的童鞋爬下來了,第一眼看到題目,感覺和去年的題目好像,也是一個類似尋路的NP問題。根據去年比賽經驗的直覺,我判斷啓發式算法太難求到最優解,求到了也難以停止迭代,加上去年對線性規劃求解器的研究,對線性規劃解此類問題已經不再生疏,當機立斷採用線性規劃。2號晚上,我們建好了模型,寫出了線性規劃matlab第一版。3號中午官網正式發佈賽題,兩個小時以後,我們就利用官方SDK完成了c++的第一版程序,幾百毫秒算出了所有case的最優解,當所有人還在研究題目,研究費用流和啓發式算法時,我們走上了優化模型和手擼求解器的不歸路。手動給隊長錢坤大佬點贊,獨立完成了一套對偶單純形+分支定界+gmi+mir割平面的線性規劃求解器。當初建好模型給他,他就和我說,就搞線性規劃,求解器你放心,交給我。對於隊長的這份魄力和編程能力我是十分敬佩的,畢竟要是這份工作放在我面前,我是一行都敲不出來的,笑。

複賽後面大佬們經常用的DSSP思路我們在初賽也嘗試過,解初賽問題效果不是很好,只能得到一個比較一般的近似解。要知道,當時大家都在追求最優解,這篇文章就被我們扔到一邊去了。參考文獻:A solution approach to the fixed charge network flow problem using a dynamic slope scaling procedure。

初賽模型

目標:成本最小

約束:整數約束;帶寬約束;消費流量約束;鏈路約束。

Tips:
1.超級源:引入虛擬源節點0,Cy爲內容服務器成本
2.消費節點壓縮:根據每個網絡節點最多僅能連接一個消費節點,每個消費節點僅能連接一個網絡節點。第一步必然是縮小拓撲,對消費節點進行前向壓縮,將消費需求壓縮到網絡節點中,即該網絡節點有相應的帶寬需求。後來大家所說的在消費節點建服務器指的就是壓縮後的有帶寬需求的網絡節點。

模型
Minimize:

minz=i=1n[ji,j=1n(uijcij)+sic0i]\min z=\sum\limits_{i=1}^{n}{\left[ \sum\limits_{j\ne i,j=1}^{n}{\left( {{u}_{ij}}\cdot {{c}_{ij}} \right)+{{s}_{i}}{{c}_{0i}}} \right]}

Subject to:

節點流量約束

j=0,ijn(uijuji)abilityisidi\sum\limits_{j=0,i\ne j}^{n}{\left( {{u}_{ij}}-{{u}_{ji}} \right)-abilit{{y}_{i}}*{{s}_{i}}}\le -{{d}_{i}}

鏈路帶寬約束

0uij,ujibij0 \le {u}_{ij},{u}_{ji}\le {b}_{ij}

i=1nabilityii=1ndi-\sum\limits_{i=1}^{n}{abilit{{y}_{i}}}\le -\sum\limits_{i=1}^{n}{{{d}_{i}}}

abilityi=j=1nbij+di{{ability}_{i}}=\sum\limits_{j=1}^{n}{{{b}_{ij}}}+{{d}_{i}}

其中,b爲每一條邊的帶寬限制,c爲每一條邊的成本,u爲每一條邊的帶寬使用情況,uxy和uyx不一樣,區分先後順序,d爲每一個網絡節點的帶寬需求,s爲是否在某點建立服務器,爲01變量。

寫公式太麻煩了。。。各種bug。。。就這樣吧。。隨緣懂。。

初賽第一次放線上用例時,模型的過於簡陋加上求解器效率問題我們case1需要80s才能迭代結束得到最優解。建模過程中,除了對求解器的優化,優化模型也可以大大提高求解速度。

首先,對邊流量變量設置爲連續變量也可以自動求出整數值,去掉對邊流量的整數約束,時間80s->30s。

然後通過降低大M法中大M的取值來降低線性規劃的下界,用時縮短到了30s->10s。大M法中的大M就是模型中的ability變量,一開始我們草率的設成了100000,影響了求解效率。大M法的介紹見此鏈接目錄第一條

最後,利用流量間的守恆關係去掉了所有的等式約束,將其與不等式約束進行了合併,這一優化直接減少了點數個變量和邊數條約束,求解效率大大提升,最終耗時10s->4s。上文所給的模型已經是合併後的模型。

之後再想優化就都是有風險的優化了,可以大大提升求解速度,但是可能會損失最優解,好在我們可以不停地上傳調參,以達到又快又準。制約線性規劃速度的最大因素就是分支定界,簡單的說,在求整數問題的鬆弛問題時(忽略整數約束),每求到一個非整數變量如0.7,我們需要把這個變量分成0和1,建立兩個子問題重新求解,由於問題是線性的,在子問題的求解時,已被分支的變量會自動求成整數,再繼續對其他變量進行分支。因此整數變量的個數越多,這顆搜索樹越深,遍歷搜索樹的速度越慢。解決這一問題最直接的方法就是減少整數變量個個數。其物理意義就是,在所有網絡節點中篩選出一個服務器候選集,只有在服務器候選集中的網絡節點有資格建立服務器。候選集建的越小,求解速度越快,當然,在小的同時,不能篩選掉最優解中的服務器。

對與候選集,我們先對所有消費節點兩兩算一次spfa,記錄亮亮消費節點最短路徑所經過的點,統計每個點出現的頻次,對出現頻次高的點納入候選集。當然還有其他參數如出入度,出入流量和等。這些都是參數,優化就是不停地調參提交,就不一一列舉了。最後我們發現,線上的例子最優解服務器全都在消費節點上,也就是用所有的消費節點當候選集。最後兩題都是100ms出解。。呵呵。。

線性規劃的方法相比於大多數人的費用流+啓發式可能思考的方向不太一樣,由於之前也沒接觸過,也就研究了短短一個月的線性規劃,可能模型裏還有很多沒有優化到的地方,表述也可能有誤,請不吝指正。

當然了,初賽的算法還是比較粗糙和傳統的,小圖由於可以算到接近最優雖然速度比較慢但成績勉強湊活,到最後八百點的圖的時候已經計算規模已經遠遠超出我們的計算能力,有時候只考慮消費節點做候選集都有可能90秒算不出解,初賽最終掉到了第六。不提了,說多了都是淚。
這裏寫圖片描述
這裏寫圖片描述

複賽

複賽的賽題又一次增加了拓撲規模,順便增設了十個服務器檔次,如果每一個檔次都對應一個整數變量的話,也就是整數變量也乘以十掐指一算,變量數炸了,我們的心也炸了。初級案例都是清一色的超時,我們開始質疑當初初賽的選擇,開始考慮後路,隊長不愧是隊長,用了一天擼了一個網絡單純型,又用了一天擼出來一套差分演化的啓發式框架,效果嘛,中游吧,說他弱吧,也能排前幾,說他強吧,離我們的目標還有一定的距離。

中間我們還嘗試過benders分解。bender分解將混合整數規劃問題分解成整數規劃部分和非整數規劃部分兩個部分,通過互相迭代收斂。非整數部分恰好就是傳統的費用流問題,可以用網絡單純型求解。剛看到benders分解的相關文獻時,我們都很興奮,按照論文所獲,這簡直是爲這道題目量身定做的一套解決方案,線性規劃+高速的網絡單純型相結合,兩者相得益彰,有種相見恨晚的感覺。但是用了幾天實現以後發現效果並不好,上界收斂太慢(還是下界來着,記不太清了)。有興趣的同學可以研究研究,如果有其他隊用了這個方法也可以和我們溝通溝通,看看是benders分解的通病還是我們自己的實現問題。

聽說DSSP在複賽顯現出了威力,只可惜它在初賽時給我留下了非常不好的印象,雖然也曾經想到過試試DSSP,不過也僅僅存留在計劃之中了,始終沒有動力再去實現一個已經被我否定了的算法。

後來。。。我們對線性規劃進行了魔改。。。中大規模基本都能算到裏最優解誤差1000以內。。。經常能比賽區第二cost低一兩萬。這裏賣個關子,挖個坑以後來填or等隊長去填。最後有驚無險的以賽區第一晉級,聽說最後全國排名也是第一,不過沒得一百分還是有些遺憾的。

這裏寫圖片描述

個人信息裏的成績被清空了,沒有cost截圖了,從聊天記錄翻到一個文字版的。
0 249379 88322 19.44
1 195885 88159 20.00
2 393215 89013 30.00
3 424572 88594 30.00

#決賽 #
決賽的問題十分有趣,和初賽複賽關係不大,是一個兩兩PK的博弈問題,爲了保證PK的公平性,每次PK五個圖,並且採用聯賽一樣的積分賽。兩個星期的時間稍顯倉促,不過,大家都很倉促,大家決賽練習賽藏代碼的保守態度,給比賽帶來了很多不確定性,測試機會稀缺,每個人的心裏都沒底。

兩次模擬排位賽我們都因爲bug失去了自我定位的機會,在bug面前,再好的策略都等於認輸,這也讓我們急的焦頭爛額,最後一週基本是在與判題組的溝通中和找bug中度過的,再也無心優化策略,直到抵達深圳,決賽現場賽的前一晚,才靜下心來通宵理了一遍代碼,改出了很多bug。。。

我們的決賽策略分爲兩個部分,初始解部分和迭代部分。和上合賽區AFH戰隊的討論中,我們理解到了初始解和投資上界的重要性。投資上界是指一個消費節點的所有鄰邊的出度之和。地圖上存在不少的點,比如需求爲1,上界爲5。這種點直接投資5個流量是穩賺不虧的,頂多平分利潤。

聰明一點的流量需求+1,更聰明一點的+2,我們直接加到上界。

當然,在交流中我們發現,+1被+2克,+2被+3克,反過來,加到上界由於佔得的點數太少,也可能被直接+0的完敗,所謂小卒子扳倒老帥。爲了避免這一情況的發生,我們將上界從小到大排序,使得初始解中達到上界的點佔初始解的三分之二,剛好滿足需求的點佔初始解的三分之一,這樣初始解既達到了一定的強度,也達到了一定的廣度。在測試過程中,這樣選出來的點比全部剛好滿足需求的選點數量少不了多少。至少可以保證我們在第一輪中利於不敗之地。

在迭代過程中,我們實現了一個非常複雜的狀態機,複雜到可能會狀態亂竄,不按我們想象中的流程去執行,決賽完了我們也不忍心再去看代碼了,怕發現漏洞以後心痛= =。

每次迭代中,對於每個點存在一下幾種狀態:我們佔了佔到的,我們佔了沒佔到的,我們沒佔對方也沒佔的,我們沒佔對方佔了的。每一個狀態都要單獨考慮。

對於我們佔到的點,我們選擇了不加流量繼續佔,隊長曾考慮過增加流量,也寫了一個粗糙的版本,被我改回來了。。。專家在這點上在PPT中對我們進行了批評,說我們的防守策略不夠好,現在再想想,這裏確實不妥,應該在賺錢了的基礎上繼續曾加流量,或許結果可以更好。對於我們佔到的點,可能是以較高代價佔的並且由於我們的流量過高對方沒有嘗試或者已經放棄。AFH戰隊提供了一個很好的偷雞策略(專家很友好的在PPT改成了投機),即連續n輪佔得某點以後,直接用最低需求(由於是預判對方已經放棄改點,一定要用最低需求去偷雞)去嘗試佔該點。一旦偷雞成功,賺得盆滿鉢滿。即使碰到頭硬的隊伍偷雞失敗(被反佔),回調流量或回調一半流量即可。偷雞策略幾乎沒有破解策略,對方的服務器設置使得對某個消費點提供的流量達不到我們所能提供的流量,就只能眼睜睜的看着我們偷,頭硬一直嘗試,會虧得更慘,畢竟撲空的概率更高,除非測出我們的偷雞觸發條件,這太難了,畢竟我們會根據偷雞成功率(對方的頭硬程度)動態調節n值。

對於我們佔了沒佔到的點,我們會對當前流量再加一個值,這個值是浮動的,根據歷史成功率變化,成功率低了值會擡高,成功率過高會降低,最終保持在一個穩定的狀態,如成功率90%左右,也算是一個濾波器吧,強行往冠軍的思路上靠- -。另外,由於我們計算了每個點的流量上界,一旦判斷該點的流量達到了上界,就會進入戰鬥狀態,戰鬥狀態是一個特殊狀態,由於戰鬥狀態至少流量打平,處於戰鬥狀態的點我們會一直佔有,直到觸發偷雞條件,判斷對方已經放棄改點,進行降流。

對於我們沒佔對面佔了或沒佔的點,這兩個的處理思路是很類似的。可以換位思考一下,對於這些點,對方上輪佔有成功或這輪準備佔有時,是把他當成一箇中立點進行佔有的,一般都是+1+2或者+n或者動態調節。我們也會通過計算佔有這些點的成功率來估計對手所加的值,從而動態調節我們所加的值,使得對這類點的佔有成功率保持在90%左右。當然這裏的成功率計算和上面的成功率計算都是不考慮已經進入戰鬥狀態的點的,這也是要單獨設立一個戰鬥狀態的原因。

終止迭代方面,我們基本上是計算新建服務器能否收回成本,一般在四十輪左右就停止迭代了,這裏考慮的不是非常周全,也沒有時間去細細考慮了。

決賽策略暫且想到這麼多吧,要是發現有遺漏的地方,以後再補充。
這裏寫圖片描述

#一點感想#
首先必須安利一波華爲公司。雖然比賽過程中出過一些問題,但是可以看出比賽過程中每一個工作人員都非常努力,非常熱情。菊廠還是十分土豪的,比賽過程中各種暖心的設計,有趣的項目,參加複賽和決賽全程報銷,獎金也十分可觀,可見一個大企業的底氣和對人才的重視和渴望。

不論是上研所還是深圳總部,都對我們的想法給予的充分的支持,在進入決賽後,幫助我們和導師溝通,幫我們和導師請假,幫我們安排專家和集訓,讓我們有了充足的時間和精力去只做一件事,我已經好久沒有這種充實而又不感到累的感覺了,比賽結束後,面對實驗室的爛攤子,感到十分空虛- -。

隊友很重要,抱大腿很重要。決賽賽題剛出的時候我很迷茫,加上實驗室師兄和導師的push,我無心準備比賽,隊長表示理解,讓我安心先做好實驗室工作,做完了再去搞比賽。隊長的導師就很支持他們搞比賽,甚至非常關心我們的比賽進程,也會在組會上發動大家的力量羣策羣力。羨慕這樣的導師~

交流很重要。去年我們進入決賽以後一直是閉門造車,連賽區內的兄弟戰隊都沒有任何溝通,最終錯誤判斷了形式,葬送了好局。今年我們雖然也會偶爾藏藏代碼,但也會一直和羣裏比較活躍的同學保持溝通,交流算法和心得,受挫的時候也會互相鼓勵。感謝同賽區的AFH,WoW,赳赳武夫,他鄉的鹹鴨蛋,圍牆編隊,USTC601,Kappon,要優雅等,感謝其他賽區的秋香,月光,吳亦凡,追日~在大家都在藏代碼保留實力的日子裏,我們坦誠相見,毫無保留,才能在不斷進步的隊伍中不被落下。

感謝自己的女朋友,連着兩個月沒怎麼好好陪她了,發朋友圈也忘記感謝她了,嗯。。。

鏈接一發月光的博客
http://blog.csdn.net/luanshaotong/article/details/72255469

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章