hdoj1874 (优先队列+Dijkstra)
分析:
一看题目, 就是求最短路, 这道题用的是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; }