hdoj1874
分析:
一看題目, 就是求最短路, 這道題用的是Dijkstra+優先隊列。先說一下Dijkstra算法:每次擴展一個距離最短的節點, 更新與其相鄰點的距離。 當所有邊權都為正時, 由於不會存在一個距離更短的沒有擴展的點,所以這個點的距離不會在改變, 保證了算法的正確性。
算法步驟如下:
G={V,E}
1. 初始時令 S={V0},T=V-S={其余頂點},T中頂點對應的距離值
若存在〈V0,V〉,d(V0,Vi)為〈V0,Vi〉弧上的權值
若不存在〈V0,Vi〉,d(V0,Vi)為∞
2. 從T中選取一個與S中頂點有關聯邊且權值最小的頂點W,加入到S中
3. 對其余T中頂點的距離值進行修改:若加進W作中間頂點,從V0到Vi的距離值縮短,則修改此距離值
重復上述步驟2、3,直到S中包含所有頂點,即W=Vi為止。
偽代碼:
將所有節點狀態初始化(標記為未計算)
設起始點s, d[s] = 0; 其他節點d[i] = MAX;
循環n次
{
在所有未標記的節點中, 選出d值最小的節點x;
標記節點x;
對於所有從x節點出發的所有邊(x, y), 更新d[y] = min(d[y], d[x] + w(x, y));
}
對應代碼:
memset(v, 0, sizeof(v)); for(int i = 0; i < n; i++) d[i] = 10e8; d[s] = 0; for(int i = 1; i < n; i++) { int mi = 10e8; for(int j = 1; j < n; j++) { if(v[j] == 0 && d[j] < mi) mi = d[j]; v[j] = 1; for(int k = 0; k < n; k++) if(d[k] < d[j] + w[j][k]) d[k] = d[j] + w[j][k]; } }
程序的復雜度為n方, 每一次都要求所有d中的最小值。 然而STL中的優先隊列priority_queue正好解決了這一問題。
#include<iostream> #include<cstdio> #include<string.h> #include<math.h> #include<algorithm> #include<queue> #include<vector> using namespace std; int n, m, s, t, v[1005]; double d[1005]; struct edge { int v; double d; }e[1005]; struct node//存儲點的信息, 起始點到x節點的最短距離d. { int x; double d; }no[1005]; bool operator< (node a, node b) { return a.d > b.d; } vector<edge> vec[1005]; double ac(int x) { memset(v, 0, sizeof(v)); priority_queue<node> q; node tem; tem.x = s; tem.d = 0; q.push(tem);//將起始點加入隊列 while(!q.empty()) { node tem = q.top();//取出d值最小的 q.pop(); int x = tem.x; if(x == t) return tem.d; if(v[x] == 1) continue; v[x] = 1; for(int i = 0; i < vec[x].size(); i++)//更新從tem.x出發的所有邊(x,y),d[y] = min(d[y], d[x]+w[x][y]) { int y = vec[x][i].v; if(d[y] > (tem.d + vec[x][i].d)) { d[y] = tem.d + vec[x][i].d; node node1; node1.x = y; node1.d = d[y]; q.push(node1); } } } return -1; } int main() { while(scanf("%d%d", &n, &m) != EOF) { for(int i = 0; i <= n; i++) vec[i].clear(); for(int i = 0; i <= n; i++) d[i] = 10e8; for(int i = 1; i <= m; i++) { int x, y, w; scanf("%d%d%d", &x, &y, &w); edge e; e.v = y; e.d = w; vec[x].push_back(e);//用vector存邊, e.v = x; vec[y].push_back(e); } scanf("%d%d", &s, &t); d[s] = 0; double ans = ac(s); if(ans == -1) printf("-1\n"); else printf("%.0lf\n", ans); } return 0; } View Code