【题目链接】
【题目考点】
1. 图论 单源最短路径
图中有V个顶点E条边,单源最短路径算法时间复杂度:
- 朴素Dijkstra算法: O ( V 2 ) O(V^2) O(V2)
- Dijkstra堆优化算法: O ( E l o g E ) O(ElogE) O(ElogE)
- SPFA算法:一般情况下
O
(
k
E
)
O(kE)
O(kE),k为顶点平均入队次数,最坏情况下
O
(
V
E
)
O(VE)
O(VE)
空间复杂度: - 邻接矩阵: O ( V 2 ) O(V^2) O(V2)
- 邻接表: O ( V + E ) O(V+E) O(V+E)
【解题思路】
该题顶点数量为100000,存储结构只能用邻接表。
如果用朴素Dijkstra算法,
O
(
V
2
)
O(V^2)
O(V2)复杂度,
V
2
V^2
V2会达到
1
0
10
10^{10}
1010,超过了
1
0
7
10^7
107,是不可接受的。所以不能用朴素Dijkstra算法。
对于复杂度为
O
(
E
l
o
g
E
)
O(ElogE)
O(ElogE)的Dijkstra堆优化算法,是可以使用的。
边数
5
∗
1
0
5
5*10^5
5∗105相比于
V
2
=
1
0
10
V^2 = 10^{10}
V2=1010是很小的,可以认为题目中给定的图都是稀疏图,k会比较小,可以使用SPFA算法。
【注意】:题目中说可能有重边和自环,这两点并不会影响Dijkstra算法和SPFA算法的运行,有重边就添加到邻接表中即可,不用特意排除重边。
【注】:邻接表的链式前向星写法相较于vector数组写法更麻烦一些,所以如无特殊说明,本人题解中默认都使用vector数组写法。要改为链式前向星写法也很容易,因而不再赘述链式前向星写法的题解。
【题解代码】
解法1:SPFA算法+邻接表
#include<bits/stdc++.h>
using namespace std;
#define N 100005
struct Edge
{
int t, w;
Edge(){}
Edge(int a, int b):t(a),w(b){}
};
vector<Edge> edge[N];
bool vis[N];//vis[i]:顶点i是否在队列中
int n, m, dis[N];//dis[i]:当前情况下v0到i的最短路径距离
void initGraph()
{
int f, t, w;
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
cin >> f >> t >> w;//从f到t权值w
edge[f].push_back(Edge(t, w));
edge[t].push_back(Edge(f, w));
}
}
void spfa(int sv)//sv起始点
{
memset(dis, 0x3f, sizeof(dis));//dis初始值为INF
queue<int> que;
dis[sv] = 0;
vis[sv] = true;
que.push(sv);
while(que.empty() == false)
{
int u = que.front();
que.pop();
vis[u] = false;
for(int i = 0; i < edge[u].size(); ++i)
{
int v = edge[u][i].t, w = edge[u][i].w;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if(vis[v] == false)
{
vis[v] = true;
que.push(v);
}
}
}
}
}
int main()
{
initGraph();
spfa(1);
cout << dis[n];
return 0;
}
解法2:Dijkstra堆优化算法+邻接表
#include<bits/stdc++.h>
using namespace std;
#define N 100005
struct Pair
{
int u, d;//u:顶点 d:距离
Pair(){}
Pair(int a, int b):u(a),d(b){}
bool operator < (const Pair &b) const
{
return b.d < d;
}
};
struct Edge
{
int t, w;
Edge(){}
Edge(int a, int b):t(a),w(b){}
};
vector<Edge> edge[N];
bool vis[N];//vis[i]表示从v0到i点的最短路径是否已经确定
int n, m, dis[N];//v0:源点 dis[i]:当前情况下v0到i的最短路径距离
void initGraph()
{
int f, t, w;
cin >> n >> m;
for(int i = 1; i <= m; ++i)
{
cin >> f >> t >> w;//从f到t权值w
edge[f].push_back(Edge(t, w));
edge[t].push_back(Edge(f, w));
}
}
void dijkstra(int sv)//sv起始点
{
priority_queue<Pair> pq;
memset(dis, 0x3f, sizeof(dis));//dis初始值为INF
dis[sv] = 0;
pq.push(Pair(sv, 0));
while(pq.empty() == false)
{
int u = pq.top().u;
pq.pop();
if(vis[u])//如果顶点u已经访问过,则跳过
continue;
vis[u] = true;
for(int i = 0; i < edge[u].size(); ++i)
{
int v = edge[u][i].t, w = edge[u][i].w;
if(vis[v] == false && dis[v] > dis[u] + w)//松弛
{
dis[v] = dis[u] + w;
pq.push(Pair(v, dis[v]));
}
}
}
}
int main()
{
initGraph();
dijkstra(1);
cout << dis[n];
return 0;
}