849. Dijkstra求最短路 I
给定一个 n
个点 m
条边的有向图,图中可能存在重边和自环,所有边权均为正值。
请你求出 1
号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1
。
输入格式
第一行包含整数 n
和 m
。
接下来 m
行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z
。
输出格式
输出一个整数,表示 1
号点到 n
号点的最短距离。
如果路径不存在,则输出 −1
。
数据范围
1≤n≤500
,
1≤m≤105
,
图中涉及边长均不超过10000。
输入样例:
- 3 3
- 1 2 2
- 2 3 1
- 1 3 4
输出样例:
3
* Dijkstra 算法:单源最短路径问题;
* 将源点的距离设置为0,接下来Nv轮循环,找出还未被加入集合且离源点最近的顶点,
* 如果时找到的这个顶点与源点有路相通,则这个顶点与源点的距离一定是这个顶点与源点之间
* 的距离最短的,不可能从源点途径另外一个顶点到达此顶点的距离更小(如果有,那么一定还有
* 与此点未连通且离源点的距离更小的点,并且是正权图,所以与前面的话(找出还未被加入集合
* 且离源点最近的顶点)矛盾),所以此算法正确;
- /**
- * Dijkstra 算法:单源最短路径问题;
- * 将源点的距离设置为0,接下来Nv轮循环,找出还未被加入集合且离源点最近的顶点,
- * 如果时找到的这个顶点与源点有路相通,则这个顶点与源点的距离一定是这个顶点与源点之间
- * 的距离最短的,不可能从源点途径另外一个顶点到达此顶点的距离更小(如果有,那么一定还有
- * 与此点未连通且离源点的距离更小的点,并且是正权图,所以与前面的话(找出还未被加入集合
- * 且离源点最近的顶点)矛盾),所以此算法正确;
- */
-
- #include <iostream>
- #include <algorithm>
-
- using namespace std;
-
- const int maxn = 510,INF=1e9;
- int G[maxn][maxn]; //邻接矩阵
- int d[maxn]; //距离数组
- bool hs[maxn]; //记录顶点是否被选择
- int Nv,Ne; //顶点数,边数
-
- void Read() //读入数据
- {
- fill(*G,*G+maxn*maxn,INF);
- cin >> Nv >> Ne;
- for(int i=0;i<Ne;++i)
- {
- int u,v,w;
- cin >> u >> v >> w;
- G[u][v]=min(G[u][v],w); //存在重边,选择权值最小的边即可
- }
- }
-
- int Dijkstra(int st) //各点到st顶点的最短距离
- {
- fill(d,d+maxn,INF);
- d[st]=0; //源点的距离为0
-
- for(int i=0;i<Nv;++i)
- {
- int u=-1,MIN=INF;
- for(int j=1;j<=Nv;++j)
- if(hs[j]==0 && d[j]<MIN)
- {
- MIN=d[j];
- u=j;
- }
-
- if(u==-1) //如果u等于-1,说明图不连通
- return -1;
- hs[u]=1;
- for(int v=1;v<=Nv;++v)
- if(G[u][v]!=INF && hs[v]==0 && d[u]+G[u][v]<d[v]) //u,v有边且v还未被选中
- d[v]=d[u]+G[u][v]; //且从源点到v途径u能使源点到v的距离变小
- }
-
- return d[Nv];
- }
-
- int main()
- {
- Read();
-
- cout << Dijkstra(1) << endl;
-
- return 0;
-
- }
850. Dijkstra求最短路 II
给定一个 n
个点 m
条边的有向图,图中可能存在重边和自环,所有边权均为非负值。
请你求出 1
号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1
。
输入格式
第一行包含整数 n
和 m
。
接下来 m
行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z
。
输出格式
输出一个整数,表示 1
号点到 n
号点的最短距离。
如果路径不存在,则输出 −1
。
数据范围
1≤n,m≤1.5×105
,
图中涉及边长均不小于 0,且不超过 10000。
数据保证:如果最短路存在,则最短路的长度不超过 109
。
输入样例:
- 3 3
- 1 2 2
- 2 3 1
- 1 3 4
输出样例:
3
* Dijkstra 算法:单源最短路径问题;
* 将源点的距离设置为0,接下来Nv轮循环,找出还未被加入集合且离源点最近的顶点,
* 如果时找到的这个顶点与源点有路相通,则这个顶点与源点的距离一定是这个顶点与源点之间
* 的距离最短的,不可能从源点途径另外一个顶点到达此顶点的距离更小(如果有,那么一定还有
* 与此点未连通且离源点的距离更小的点,并且是正权图,所以与前面的话(找出还未被加入集合
* 且离源点最近的顶点)矛盾),所以此算法正确;
*
* 堆优化版的 Dijkstra 算法和朴素版的算法思想一样,只不过求解还未被加入集合且离源点
* 最近的顶点时,用最小堆来求,这样算法时间复杂度可以下降为 O(n*logn);
- /**
- * Dijkstra 算法:单源最短路径问题;
- * 将源点的距离设置为0,接下来Nv轮循环,找出还未被加入集合且离源点最近的顶点,
- * 如果时找到的这个顶点与源点有路相通,则这个顶点与源点的距离一定是这个顶点与源点之间
- * 的距离最短的,不可能从源点途径另外一个顶点到达此顶点的距离更小(如果有,那么一定还有
- * 与此点未连通且离源点的距离更小的点,并且是正权图,所以与前面的话(找出还未被加入集合
- * 且离源点最近的顶点)矛盾),所以此算法正确;
- *
- * 堆优化版的 Dijkstra 算法和朴素版的算法思想一样,只不过求解还未被加入集合且离源点
- * 最近的顶点时,用最小堆来求,这样算法时间复杂度可以下降为 O(n*logn);
- */
-
- #include <iostream>
- #include <algorithm>
- #include <queue>
- #include <vector>
-
- using namespace std;
-
- struct ENode
- {
- int v,w;
- };
-
- typedef pair<int,int> PII;
-
- const int maxn = 1.5e5+10 ,INF=1e9;
- vector<ENode> Adj[maxn]; //邻接表int d[maxn];
- int d[maxn]; //距离数组
- bool hs[maxn]; //记录顶点是否被选择
- int Nv,Ne; //顶点数,边数
-
- void Read() //读入数据
- {
- cin >> Nv >> Ne;
- for(int i=0;i<Ne;++i)
- {
- int u,v,w;
- cin >> u >> v >> w;
- Adj[u].push_back({v,w});
- }
- }
-
- void Dijkstra(int st) //各点到st顶点的最短距离
- {
- //priority_queue 默认为小根堆,但是为什么非要加后面两句呢?
- //priority_queue<PII> q 就表示最小堆,或许是pair的缘故吧;
- //知道缘故了,priority_queue 默认为大根堆;
-
- priority_queue<PII,vector<PII>,greater<PII> > q;
- q.push({0,st});
- fill(d,d+maxn,INF);
- d[st]=0;
-
- while(q.size())
- {
- PII top=q.top();
- q.pop();
-
- int u=top.second;
- if(hs[u])
- continue;
- hs[u]=1;
-
- for(int i=0;i<Adj[u].size();++i)
- {
- int v=Adj[u][i].v,w=Adj[u][i].w;
- if(hs[v]==0 && d[u]+w<d[v])
- {
- d[v]=d[u]+w;
- q.push({d[v],v});
- }
- }
- }
- }
-
- int main()
- {
- Read();
-
- Dijkstra(1);
-
- if(d[Nv] == INF)
- cout << -1 << endl;
- else
- cout << d[Nv] << endl;
-
- return 0;
-
- }