【日常學習】【Dijkstra堆最佳化】codevs2038 香甜的黃油題解,dijkstracodevs2038
轉載請註明出處 [ametake著作權]http://blog.csdn.net/ametake
先放上題目,出自USACO
題目描述
Description
農夫John發現做出全威斯康辛州最甜的黃油的方法:糖。把糖放在一片牧場上,他知道N(1<=N<=500)只奶牛會過來舔它,這樣就能做出能賣好價錢的超甜黃油。當然,他將付出額外的費用在奶牛上。
農夫John很狡猾。他知道他可以訓練這些奶牛,讓它們在聽到鈴聲時去一個特定的牧場。他打算將糖放在那裡然後下午發出鈴聲,以至他可以在晚上擠奶。
農夫John知道每隻奶牛都在各自喜歡的牧場獃著(一個牧場不一定只有一頭牛)。給出各頭牛在的牧場和牧場間的路線,找出使所有牛到達的路程和最短的牧場(他將把糖放在那)。
輸入描述
Input Description
第一行: 三個數:奶牛數N,牧場數P(2<=P<=800),牧場間道路數C(1<=C<=1450).
第二行到第N+1行: 1到N頭奶牛所在的牧場號.
第N+2行到第N+C+1行: 每行有三個數:相連的牧場A、B,兩牧場間距(1<=D<=255),當然,串連是雙向的.
輸出描述
Output Description
一行 輸出奶牛必須行走的最小的距離和.
範例輸入
Sample Input
3 4 52341 2 11 3 52 3 72 4 3
3 4 5
範例圖形
P2 P1 @--1--@ C1 \ |\ \ | \ 5 7 3 \ | \ \| \ C3 C2 @--5--@ P3 P4
範例輸出
Sample Output
8
{說明: 放在4號牧場最優. }
這道題目得耗了我二十多個小時 從最早的SPFA裸,到SLF和LLL最佳化,再到雙結構體的可憐堆最佳化Dijkstra= =說起來都是淚啊TUT
根據朱全民在NOI導刊上的文章來看,此題最好的方法應該是SPFA
但是顯然codevs加強了資料 邊數劇增 導致SPFA退化到比裸的Dijkstra還慢 因為SPFA時間複雜度為O(km),m是邊數,k期望為2,邊數很大(比如這道題目n*(n-1),n是點數)的情況下,比dij的O(n²)顯然要慢。
正如我們之前總結過的,遇到稠密圖,SPFA很是苦手。
加了兩個最佳化,原理是把可以鬆弛的邊放在隊列前面,優先隊列實現。但還是逾時。如下
可以看出,隨著資料規模增大,時間劇增,因為邊數二次函數增長
而如果用最佳化的Dij,效果就要好得多。堆最佳化的原理是運用一個最小堆(c++可以通過STL的priority_queue實現),使“尋找dist最小邊貪心”的複雜度降低到logn,而如果運用鄰接表格儲存體,直接尋找能更新的點,更新dist的複雜度最大是n。因此堆最佳化後複雜度為O(nlogn),顯然在稠密圖中會大大降低時間複雜度。而相對於SPFA空間複雜度並沒有增多很多(尤其是SPFA加了最佳化儲存規模基本是一樣的,也是寫結構體+優先隊列重載)。
我們來看一下dijkstra最佳化時間:
顯而易見,小資料差別並不大,dijkstra還要慢一些,而一旦資料規模爆表,dij優勢不言而喻。大資料要快10倍。
接下來放上這幾次嘗試的代碼吧
這是最原始的SPFA 裸的可以當模板
SPFA還可以用SLF和LLL最佳化 兩個最佳化本質是一樣的,可以用結構體+重載小於符號+優先隊列實現 參見“瑪麗卡”
接下來是原始版的dijkstra堆最佳化 和最終版區別是 元素一次性全部入隊 每次最小元素出隊並調整其他元素位置 這個程式WA了 但本身演算法應該沒有問題 我不想調試了所以先放到這裡請注意:這是
錯誤的程式
接下來是最終版 像bfs那樣 每次擴充出新的節點入隊
另外,方便pascal同學們,最後附上朱全民老師pascal代碼對這個題目的講解。但是請注意,朱全民老師講解用的是USACO未經處理資料,是稀疏圖,最優解SPFA
——一葉扁舟輕帆卷,暫泊楚江南岸。