1. 最短距离
来源Indeed笔试题
原题链接
题目描述
有 \(N\) 个村庄,编号 \(1\) 到 \(N\)。
村庄之间有 \(M\) 条无向道路,第 \(i\) 条道路连接村庄 \(a_i\) 和村庄 \(b_i\),长度是 \(c_i\)。
所有村庄都是连通的。
共有 \(K\) 个村庄有商店,第 \(j\) 个有商店的村庄编号是 \(x_j\)。
然后给出 \(Q\) 个询问,第 \(k\) 个询问给出一个村庄的编号 \(y_k\),问该村庄距离最近的商店有多远?
输入格式
第一行包含两个整数 \(N\),\(M\)。
接下来 \(M\) 行,每行包含三个整数 \(a_i\),\(b_i\),\(c_i\),表示第 \(i\) 条道路连接村庄 \(a_i\) 和村庄 \(b_i\),长度是 \(c_i\)。
再一行包含整数 \(K\)。
接下来 \(K\) 行,每行包含一个整数 \(x_j\),表示第 \(j\) 个有商店的村庄编号是 \(x_j\)。
再一行包含整数 \(Q\)。
接下来 \(Q\) 行,每行包含一个整数 \(y_k\),表示询问编号为 \(y_k\) 的村庄与其距离最近的商店之间的距离。
输出格式
对于每个询问,输出该询问的结果。
数据范围
\(2≤N≤105\),
\(N−1≤M≤min(\frac{N(N−1)}{2},105)\),
\(1≤Q≤105\),
\(1≤K≤N\),
\(1≤c_i≤10000\)
输入样例
7 7
1 2 5
1 4 3
2 3 2
2 5 1
3 6 7
5 6 8
6 7 6
3
7
5
4
7
1
2
3
4
5
6
7
输出样例
3
1
3
0
0
6
0
算法:(堆优化的\(dijkstra\)) \(O(mlogn)\)
算法内容
-
题意分析:每一个带有商店的村庄都是一个起点(不妨设分别为\(s_1\), \(s_2\), \(s_3\),···, \(s_k\)),所以共有\(k\)个起点,还有有一张包含所有村庄的图;共有\(q\)个查询,在每一次查询中会从这张图中给我们提供一个终点,我们需要输出从起点到终点的最短路径。
-
我们可以采取\(dp\)的分析思路,按照起点将所有路径分为\(k\)类,求出每一类的最小值取\(min\)即为所有路径的最小值。那么我们如何实现呢?我们可以在所有的\(k\)个起点前面加上一个虚拟的源点,这样就转化为到从源点到不同的终点的最短路问题。
- 由于\(n\)和\(m\)都是\(10^5\),为稀疏图,朴素版的\(dijkstra\)时间复杂度为\(O(n^2)\),会超时,所以应该用堆优化的\(dijkstra\)
C++代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII; //距离,编号
const int N = 1e5 + 10, M = 3 * N;
int n, m, k, q;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
bool st[N];
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dijkstra()
{
priority_queue<PII, vector<PII>, greater<PII>> heap;
memset(dist, 0x3f, sizeof dist);
heap.push({0, 0});
dist[0] = 0;
while (heap.size())
{
auto t = heap.top();
heap.pop();
int ver = t.y;
if (st[ver]) continue;
st[ver] = true;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[ver] + w[i])
{
dist[j] = dist[ver] + w[i];
heap.push({dist[j], j});
}
}
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while (m -- )
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
cin >> k;
while (k -- )
{
int x;
scanf("%d", &x);
add(0, x, 0); //加一个虚拟源点
}
dijkstra();
cin >> q;
while (q -- )
{
int x;
scanf("%d", &x);
printf("%d\n", dist[x]);
}
return 0;
}
标签:图论,ver,int,dijkstra,村庄,heap,dist From: https://www.cnblogs.com/lhycoder/p/17294461.html