Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8219 Accepted Submission(s): 2456php
[題目連接] http://acm.hdu.edu.cn/showproblem.php?pid=3790算法
【解題思路】Dijk + heap【單元最短路】既然有兩考慮的因素,並且分優先,那麼優先隊列排列比較的時候就先考慮路徑長度,在路徑長度相等的前提下在考慮花費的大小,即路徑小花費少的先出,在細節進隊的時候也是這樣考慮,過一遍Dijk最後輸出須要的值spa
【PS】剛學最短路,一開始沒考慮清楚,不知該如何下手,但知道問題出在對Dij算法的掌握程度上,若是像以前的剛學的最短路情形(只有一個考慮的元素),估計也會敲出來,後來本身實現了這題的代碼時,發現思路也是同樣的,單個因素的最短路中, 進隊的時候判斷可否進隊用的是小於關係運算符,若是也存在多條最短路的時候,由於小於關係運算的緣故,這時起始點到這個點的相同長度的最短路徑不會進隊列(由於已有進入隊列的相同長度的路徑),但若是還有考慮的因素時,這是就不同了,像這題,在路徑長度的判斷上就要改用小於等於關係運算符,由於在路徑長度相等的時候,其還有次要考慮因素,這時,次要考慮因素的比較上就須要用到小於關係運算符。code
一開始考慮錯誤的方向是將從源點到終點整條最短路徑與其最小花費進行權衡,沒有考慮到:在優先隊列中,一出隊列,若是以前沒有被訪問,那麼就意味着鎖定了這個點的最短路徑和最小花費,再次困擾的是此時的點是如何如何影響到後續點的路徑和花費,因此不敢肯定了是否該這樣進行。最後想到:假設其(當前出隊列的點)只有一條最短路徑,那麼就能夠放心的往下進行,由於這種狀況回到了單個考慮因素的狀況嘛,若是有多條最短路徑呢?那麼其確定都在隊列當中,你如今就要作的就是在其中找到一條最優的(根據次要因素判斷)出隊列才行,根據本身的理解,感受仍是不太夠成熟 ^_^blog
一直不敢對Dij等各類算法用得義正詞嚴,該學的是思想,這是最重要的,別拿着別人的算法用得好像是自家的似的。隊列
1 #include <cstdio> 2 #include <queue> 3 #include <cstring> 4 5 using namespace std; 6 7 const int NV = 1002; 8 const int NE = 100002; 9 const int INF = 1<<30; 10 int ne, nv, term, tern, tot; 11 bool vis[NV]; 12 int dist[NV]; 13 int purse[NV]; 14 struct Edge{ 15 int v, cost, money, next; 16 Edge(){} 17 Edge(int a, int c, int m){v = a, cost = c, money = m;} 18 Edge(int a, int c, int m, int d){v = a, cost = c, money = m, next = d;} 19 bool operator < (const Edge& x) const 20 { 21 if(cost != x.cost) return cost > x.cost; 22 else return money > x.money; 23 } 24 }edge[NE]; 25 int eh[NV]; 26 27 void Dij(int s) 28 { 29 for(int i = 1; i <= nv; ++i) purse[i] = dist[i] = i == s ? 0 : INF; 30 priority_queue<Edge> que; 31 que.push(Edge(s, 0, 0)); 32 while(!que.empty()) 33 { 34 Edge tmp = que.top(); 35 int u = tmp.v; 36 que.pop(); 37 if(vis[u]) continue; 38 vis[u] = true; 39 for(int i = eh[u]; i != -1; i = edge[i].next) 40 { 41 int v = edge[i].v; 42 if(!vis[v] && dist[v] >= edge[i].cost + dist[u]) 43 { 44 if(dist[v] > edge[i].cost + dist[u] || 45 (dist[v] == edge[i].cost + dist[u] && purse[v] > edge[i].money + purse[u])) 46 { 47 dist[v] = edge[i].cost + dist[u]; 48 purse[v] = edge[i].money + purse[u]; 49 que.push(Edge(v, dist[v], purse[v])); 50 } 51 52 } 53 } 54 } 55 return; 56 } 57 58 void addedge(int u, int v, int cost, int money) 59 { 60 Edge e = Edge(v, cost, money, eh[u]); 61 edge[tot] = e; 62 eh[u] = tot++; 63 return; 64 } 65 66 int main() 67 { 68 #ifndef ONLINE_JUDGE 69 freopen("input.txt", "r", stdin); 70 #endif 71 while(scanf("%d%d", &nv, &ne) != EOF && nv+ne) 72 { 73 memset(eh, -1, sizeof(eh)); 74 memset(vis, false, sizeof(vis)); 75 term = tern = tot = 0; 76 int u, v, cost, money; 77 for(int i = 0; i < ne; ++i) 78 { 79 scanf("%d%d%d%d", &u, &v, &cost, &money); 80 addedge(u, v, cost, money); 81 addedge(v, u, cost, money); 82 } 83 int s, t; 84 scanf("%d%d", &s, &t); 85 Dij(s); 86 printf("%d %d\n", dist[t], purse[t]); 87 } 88 return 0; 89 }