2017 華爲軟件精英挑戰賽

2017-04-27

複賽成績好渣好渣啊。怪複賽初期沒有投入,第一週完全沒管了。導致後面跟不上節奏了。
http://pan.baidu.com/s/1boOCQTL 初賽複賽代碼都放到雲盤了。
看一下代碼就能很清楚知道算法了。
複賽太差就不講思路了。
說說初賽:
1.採用模擬退火的思路做的,這個其實是其他隊伍說效果不錯,我才採用的
2.模擬退火會陷入局部最優,我固定T爲10了
3.操作只有增加點、刪除點、交換點。由於後期交換的作用大
4.迭代次數很關鍵,由於初中級case迭代次數很多。增加、刪除、交換點的情況數是可以固定的,所以是可以枚舉的,
因爲這裏做了一個操作,一旦所有轉移情況都試過了就退出,因此我們隊初賽的時候是可以控制時間的,初中級常常是滿分。
5.獲知大佬測試出直連點就能有最優解,所以只用直連點就好啦,可以加速很多
6.由於局部最優解可能很多,所以記錄那些狀態是訪問過的,萬一跳到這個狀態就不訪問了,狀態去重。可以用unorder_map做,我直接用bitset搞的
回答上一次的問題:
1.初始化:應該是指拋棄一些點吧,這樣初始的時候服務器數量就少了
2.T=10
3.評估函數也是大佬們發現的,直連需求越大的點,越容易是最優解的點,所以直連點分類,需求越大的點越容易保留,越不容易交換,越容易加入。這樣可以加速迭代吧。
初賽怎麼做了忘記了。。尷尬。。。。。但是主要思考就這些吧。

對了,其實局部最優我們也沒有解決,測試樣例有些解容易陷入一個較好解,不是最優的。


2017-4-5 新的開始(二)

最後一天咯,祝大家好運。然後我們隊已棄療,不打算修改了。以下幾點供大家思考:

1.初始化,直連點初始化時一個很優秀的方案,但是初始化的時候你其實可以把服務器限定在一個比較小的範圍

2.局部最優解問題,更新的概率不要設置死爲0,因爲很容易陷入局部最優。

3.迭代優化,隨機算法有很多無效的迭代,雖然迭代次數很難提升了,但是能讓有效迭代提高就能收斂的更好,那麼如何讓迭代效率更高呢,那就是設置評估函數,對於點有個概率留在或者拋棄在答案集合中。

以上三個問題解決了,進32應該可以吧,希望不要打臉,明天一看大佬們把我們隊打下去了,那我就哭了。。。


2017-4-1 戰鬥剛剛開始,最後一更~

最後一更:在數據更新以後終於進了前十。 好開心的。然而真的戰鬥纔剛剛開始。大家祝我們好運吧。歡迎各位大佬私信交流。


寇嘚蝦 LG 天津大學 寇嘚蝦,我們走

最後附上官方樣例的解,僅供參考。祝大家好運

http://paste.ubuntu.com/24291322/ 這裏有文本數據。 最後兩列是最後更新的時間和迭代次數。總共使用80s每個case。

附:最後時刻努力準備提排名,無有效交流將不再回復。


PS:這篇文章訪問量上100000我就公佈第一版的源代碼

看完覺得有用,粉我啊~~~我還要更新的

我的百度網盤:http://pan.baidu.com/s/1boOCQTL 資料放這裏了(刪除算法模板,視頻裏說會查重。嚇死我了。還有判斷數據是否合法的代碼。。。。。)

type	case	nodenum	linknum	costnum	servercost	widthNeed	answer	servernum	lastUpdatetime	dieDaiNum
0	0	160	620	72	400	5491	22243	38	4987744	        8833
0	1	160	606	72	400	5108	21932	41	17154391	38128
0	2	160	621	72	400	5587	21312	38	34257124	72893
0	3	160	611	72	400	5785	23158	43	542440    	1314
0	4	160	627	72	400	5139	22127	39	6226106 	10107
0	5	160	620	72	400	5431	21476	36	1458696 	1814
0	6	160	614	72	400	5223	22703	40	15190346	32832
0	7	160	617	72	400	5768	22093	43	13806073	30137
0	8	160	609	72	400	5276	21986	38	1642086 	2090
1	0	300	1135	135	400	10132	42147	75	39272372	35807
1	1	300	1134	135	400	8905	40585	68	74427884	58061
1	2	300	1155	135	400	9179	40579	70	67818817	60529
1	3	300	1175	135	400	10485	42189	77	34735045	32831
1	4	300	1169	135	400	9928	40938	70	7346828 	5314
1	5	300	1163	135	400	10679	42468	77	50988996	56625
1	6	300	1176	135	400	10347	42804	76	35248808	32830
1	7	300	1149	135	400	9503	39523	68	61649821	44102
1	8	300	1169	135	400	11077	43475	86	3845503 	3816
2	0	800	3022	360	400	23491	105329	178	63354612	11524
2	1	800	2994	360	400	25217	108611	199	75847206	19706
2	2	800	3016	360	400	25636	110269	199	72180714	11210
2	3	800	2991	360	400	24461	107534	185	78103581	10801
2	4	800	3021	360	400	26467	110323	196	77699022	9362
2	5	800	2939	360	400	24854	109330	187	65916916	10888
2	6	800	2969	360	400	25711	111035	198	71784436	16795
2	7	800	2976	360	400	25252	111014	199	63073486	14300
2	8	800	2959	360	400	25305	110238	200	58176184	12654


2017-3-26 我把思路完整說一遍吧

補充:計時器的問題,費用流800個點跑一遍最多1s,所以我用的是clock()函數計時的。每次跑完費用流,判斷用時大於80s了就結束,輸出。
#include<ctime>
clock_t start = clock();
do{

}while((clock()-start)  < 80*CLOCKS_PER_SEC)



雖然進不了64,但是我還是有話說的。(不懂的先學習一下什麼是網絡流,然後幾個詞彙)

我的思路:

根據前面的內容我們建圖,每個網絡結點跟匯點連邊代價爲服務器的代價。然後初始圖就建好了,這裏沒有考慮已經選擇了一個點當服務器的情況。那我們怎麼解決呢。

:::最小費用流,跑出一個路線對吧,然後判斷這個路線上除了匯點的最後一個點是不是是服務器,如果不是服務器就標記成服務器,然後把這個點連像匯點的邊的代價設置爲0.!!!對就是這一步,然後一直重複做就行了。

當然細節處理還是要的,比如這個時候的最短路就是路徑長度-服務器費用了。這個方法是一種貪心的策略,還是會有問題的,所以你要想一個策略讓最後的結果能夠收斂,比如隨機初始化幾個結點爲服務器,然後你就可以得到一個不同答案了。重複隨機選個最小值。相信我,800個點的1s中不用就可以跑完,至少可以迭代80次。收斂策略好的話真的能取得一個可以的解。


解答問題:

1. 最後一定是可行解碼?

一定!因爲是最小費用最大流,最大流就是滿足條件的可行方案。把費用流得到殘留網絡的補建一個新圖,(就是說一條邊你用了多少流量,新圖就連一條多少流量的邊),然後從服務器點搜索到消費結點,一定是一條路徑!而且絕對不會有環!相信我,騙你的話我的程序是會死循環的。

當然其實這個策略只是得到一個貪心的服務的安置位置。得到的最小費用也不是這個擺放位置下的最小費用(這個trick不隱藏),你要新建一張圖,服務器更匯點連邊,不是服務器不跟匯點連邊,然後再跑一遍費用流,再從這個殘留網絡去找答案,會有更好的值。

dfs,bfs隨便用,可以看成有向無環拓撲圖,怎麼搜都是一樣的。



2.怎麼判讀輸出是否正確呢?

我的百度網盤都提供一個代碼了啊!親,你看一看能看懂的,用就是了,別客氣。

有問題的答案代碼會提示錯誤的。


3:還是可行解的問題,

殘留網絡建立新圖以後,每條邊記錄的是流量(新圖不需要費用信息,只需要知道流量信息),從服務器出發只有流量大於0的邊才搜索,然後取服務器到消費點的路徑上的最小流量值,就是這個路徑上的最大流量。搜索完這個路徑,更新一下路徑上的流量 ,把他們減去路徑上那個最小流量值。

搜索完以後,這個新圖所有的邊的流量都會是0!真的,你思考一下就知道了。


4.怎麼選擇服務呢

博主也是麻瓜啊,進不了64,我只會隨機,而且我只有週末的時候能寫代碼。況且週末我也有別的任務要完成,好苦逼的。

隨機大法好,迭代就行了。你要是嫌棄用用什麼蟻羣、遺傳的策略搞一搞也許效果好一點。


5隨機搞的效果怎麼樣:

我現在還沒用迭代的方法:只計算一次得到的結果如下case0-5的,費用+服務器數量。

甚至我想告訴你們,有一個可調的參數是。網絡結點到匯點的邊的代價,你可以根據消費結點的情況設置這個代價,不一定是服務器的成本!而且這個方式真的能好一點,我新的結果就是服務器代價/10然後提交就比原始的好一點了。

3月25日
3294
9
2923
9
2032
9
2631
5
3046
9


2017-3-22 這裏說說最小費用流、網絡流

更過代碼可以看我的博客圖論專欄,以及百度網盤中acm模板
網絡流的知識:百度百科
http://baike.baidu.com/link?url=meSaxKRxidfgT7eKYdZJHjbzFBKVlkgdpuQkdsTzoVIysVOvZCQuF30WsZl9gBeD2as--oYCPLHt25-NdK5Qg4O3Iprrhx5r1FSGc-C_EqAsyV9906aG_BGkiOl8s-2R


我簡單說說:
要利用網絡流算法,首先要構造一張圖,這個圖要滿足有一個源點,匯點。 源點只能流出,匯點只能流入。
直觀來說就相當於一個水管的網絡,求得一種流水方式,是的起點到終點每秒鐘的流量最大。費用流呢,是每條管道每個單位流量有費用,保證最大流量的情況下費用最少
官方給出的圖已經包含了這個圖中的主要信息,流量上限以及費用。
我們缺少的是怎麼建立只有源點,匯點的圖:
建圖方式:  建立虛擬起點S,虛擬重點T, 
對於每個消費結點ID 建立一條 S->ID的邊,費用爲0,流量爲消費結點的需求
對於每個網絡中的結點(可以當服務器的)NID, 建立NID->T,費用爲0,流量爲無窮(很大的數字)
然後對於消費結點和直接相連的網絡結點 建立 ID->NID,流量爲消費結點的需求,費用爲0,。

這樣就構造了一張不包含服務器費用的圖。跑一遍最小費用流就能獲得在不考慮服務器費用的情況下得到的最小費用(那麼其實就可以當做是費用下界,同樣也能得到上界。。。嘿嘿嘿,這裏其實就是每個消費結點連接的網絡結點都是服務器的情況)。
當然你還需要一些別的操作來實現最後的目標。。    1. 隨機初始化一些點是服務器,然後不是服務器的點不連接T的邊,這樣得到的就是通過這幾個初始服務器得到的最小費用。那可以通過隨機設置一些方案來選擇最好的方案。

跑完費用流,我們要求一個方案。要新建圖,圖上的結點還是原來的結點,但是對於一條邊,如果這條邊 u->v 的流量被佔用了x,那麼v->u建一條流量爲x的邊。
這個時候不需要考慮費用了,因爲你的費用在費用流計算的時候已經得到了。
建立完圖不用什麼網絡流的優化算法了,直接深度優先搜索DFS(然後還是要控制一下流量的,這條路徑上最小的流量就是這條路徑的流量),從T到S,搜到一條路徑,就是一條要輸出的路徑(扣除T,S)。
然後方案就出來了。

下面附上相關代碼和對應的ACM題,幫助大家理解。
-------------------嘿嘿,怎麼選服務器不要問我,我現在就是隨便選的一組,然後就輸出了,
不過等我有了新版本的時候,我考慮一下把第一版本的思路放出來。
對於代碼有什麼不懂的,先看資料再嘗試問我。


費用流代碼SPFA

http://blog.csdn.net/firenet1/article/details/47311839


網絡流dinic算法

http://blog.csdn.net/firenet1/article/details/46990045

網絡流sap算法

http://blog.csdn.net/firenet1/article/details/41659367




2017-3-20  今天終於得分了了::::::::::

首先感謝 華爲_判題_吳賀猛 幫助我找到了重要的原因。


我提交了很多遍,都是0分, 你想知道爲什麼0分嗎?

明細:
TOPO0 Result error! Score:0,Cost:0,UseTime:0 TOPO1 Result error! Score:0,Cost:0,UseTime:0
用例名稱 Cost Time(ms) 用例得分
0 0 0 0.00
1 0 0 0.00

第一條: 本地運行都沒有問題,交上去確實0分,可能是編譯不通過 第一你要下載最新的jdk

CPU:Intel(R) Xeon(R) CPU E5-2680 V4 @ 2.40GHz
內存:2G
內核:單核
編譯器:gcc 4.8.4;java 1.7.0_95;
操作系統:linux Ubuntu 14.04.4 LTS 64位,內核版本 Linux version 3.13.0-108-generic
SDK:爲方便選手做題,分別提供c++(兼容c)和Java SDK包供參考(見賽題下載包),詳細描述信息請見SDK目錄下的readme.txt。


我的百度網盤裏放了cmake的源文件,可以用來編譯(也放了官方新的jdk)

http://pan.baidu.com/s/1boOCQTL


哦,安裝環境前,我用了sudo apt-get remove gcc (cmake) 把原來的東西先清理掉了。

Ubuntu下載

http://www.ubuntu.org.cn/download/alternative-downloads

http://cdimage.ubuntu.com/releases/14.04.5/


編譯器:vim或者其他的編譯器很多,本人熱愛codeblocks 16.10 

https://launchpad.net/~damien-moore/+archive/ubuntu/codeblocks-stable



官方的運行環境如上,對於linux系統,哪個版本影響並不大,只要64位就可以,但是gcc,g++確實很重要

gcc,g++的安裝 http://www.linuxidc.com/Linux/2014-03/97445.htm  如果是新手就嚴格按要求來吧,

sudo apt-get install libgmp-dev
sudo apt-get install libmpfr4 libmpfr-dev
sudo apt-get install libmpc-dev libmpc2
sudo apt-get install libtool
sudo apt-get install m4
sudo apt-get install bison
sudo apt-get install flex
sudo apt-get install autoconf

不過上面幾個步驟好像沒有順利通過,但是我也不管了

sudo add-apt-repository ppa:ubuntu-toolchain-r/test 
sudo apt-get update

sudo apt-get install gcc-4.8 
sudo apt-get install g++-4.8 
sudo apt-get install gcc-4.8-multilib 
sudo apt-get install g++-4.8-multilib 
sudo apt-get install gcc-4.8-doc 
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20 
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 20 
sudo update-alternatives --config gcc 
sudo update-alternatives --config g++

sudo apt-get update 
sudo apt-get upgrade -y 
sudo apt-get dist-upgrade

上面gcc,g++不要偷懶,少了也不能編譯的,最後一步我嫌棄下載太多東西,終止掉了,但是不影響。

搞定了這個,環境就跟服務器上的基本一致了。


然後安裝cmake,讀readme裏,下面一個命令搞定,但是要用root權限

 $ ./bootstrap && make && make install


然後環境就搞定了。

但是我遇到了如下問題

make[2]: *** [CMakeFiles/cdn.dir/deploy.cpp.o] Error 1
make[1]: *** [CMakeFiles/cdn.dir/all] Error 2
make: *** [all] Error 2
死活不知道原因,但是其實仔細看編譯信息,就會發現有編譯錯誤,所以導致這個報錯。

因此修改代碼就可以了。本地能運行服務器也就能運行了。


至於中文註釋什麼的都沒問題了,剛開始我嘗試各種方式,看論壇裏的文章規避問題,還是不行。

然後吳老師給我發了編譯報錯的信息,推薦我使用gcc 4.8. 我看到編譯錯誤以後手動修改了壓縮包,提交以後就有分了。

然後修改環境以後自動編譯得到的包就能提交運行得分了。




2017-3-19 第一版程序::::::

官方題目中的例子,但是我數了下只有44條邊,用於測試吧 標記爲case-1.txt (輸錯了我也不驗證了,累死人)

28 44 12

100

0 1 20 1
0 2 16 1
0 3 13 1
0 6 13 2
0 7 25 2
0 8 36 2
0 9 14 2
0 16 8 2
0 26 13 2
1 2 5 2
1 3 11 1
1 15 16 2
1 16 24 2
1 18 31 2
1 19 26 2
2 3 7 1
2 4 37 2
2 20 2 2
2 21 5 2
2 25 24 2
3 19 24 2
3 24 17 2
4 5 26 1
4 6 12 1
5 6 14 1
8 21 36 5
9 10 6 1
9 11 14 1
10 11 9 1
10 26 11 5
12 13 15 1
12 14 9 1
12 15 12 1
13 15 27 1
13 14 11 1
14 15 19 1
17 18 22 1
21 22 22 1
21 23 18 1
21 24 14 1
22 23 23 1
22 24 11 1
23 24 23 1
26 27 19 1


0 8 40 
1 11 13
2 22 28
3 3 45
4 17 11
5 19 26
6 16 15
7 13 13
8 5 18
9 25 15
10 7 10
11 24 23


第一版程序得到的答案:

以下是附件中的幾個測試樣例的解:第一版能跑通就很開心了。。。。。當然我問過去年打比賽的賽友,結果比我的好多了。
case-1.txt: Total cost:1123 Server num: 5 需要總流量: 257  提供的流量: 257     
case0.txt: Total cost:4160 Server num: 4 需要總流量: 303  提供的流量: 303       
case1.txt: Total cost:2951 Server num: 6 需要總流量: 381  提供的流量: 381       
case2.txt: Total cost:3864 Server num: 4 需要總流量: 431  提供的流量: 431       
case3.txt: Total cost:2765 Server num: 3 需要總流量: 340  提供的流量: 340       
case4.txt: Total cost:2525 Server num: 5 需要總流量: 284  提供的流量: 284       

百度網盤文件: http://pan.baidu.com/s/1pL35Ull

check.cpp 判斷一個輸出結果是否正確,有問題會輸出一些信息,最後一行輸出是這個解的一些信息,費用、服務器數量

case*.txt是數據文件

case*answer.txt 是一個解


別人的抄襲一下;

網絡結點數: 28, 網絡鏈路數: 45, 消費結點數: 12 
每臺服務器的費用爲: 100  
最小費用:783 
服務器結點:0, 3, 22

官方 case0
網絡結點數: 50, 網絡鏈路數: 96, 消費結點數: 9 
每臺服務器的費用爲: 260 
最小費用:2042 
服務器結點:7, 13, 15, 22, 37, 38, 43

官方 case1
網絡結點數: 50, 網絡鏈路數: 97, 消費結點數: 9 
每臺服務器的費用爲: 280 
最小費用:2136 
服務器結點: 6, 7, 13, 17, 35, 41, 48

官方 case2
網絡結點數: 50, 網絡鏈路數: 113, 消費結點數: 9 
每臺服務器的費用爲: 300  
最小費用:1692 
服務器結點: 12, 18, 23, 29, 31, 38, 48

官方 case3
網絡結點數: 50, 網絡鏈路數: 97, 消費結點數: 9 
每臺服務器的費用爲: 300  
最小費用:2111 
服務器結點: 10, 22, 26, 29, 35

官方 case4
網絡結點數: 50, 網絡鏈路數: 99, 消費結點數: 9 
每臺服務器的費用爲: 240  
最小費用:1967 
服務器結點: 12, 15, 20, 22, 26, 37, 48
這個是別人發過的





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