Welcome to LHY's Blog!

图论

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\)个起点前面加上一个虚拟的源点,这样就转化为到从源点到不同的终点的最短路问题。

image

  • 由于\(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;
}

posted @ 2023-04-06 22:17  LiHaoyu  阅读(74)  评论(0)    收藏  举报