【蓝桥杯集训·每日一题】AcWing 1488. 最短距离

简介: 文章目录一、题目1、原题链接2、题目描述二、解题报告1、思路分析2、时间复杂度3、代码详解三、知识风暴Dijkstra算法

一、题目

1、原题链接

1488. 最短距离

2、题目描述

有 N 个村庄,编号 1 到 N。

村庄之间有 M 条无向道路,第 i 条道路连接村庄 ai 和村庄 bi ,长度是 ci。

所有村庄都是连通的。

共有 K 个村庄有商店,第 j 个有商店的村庄编号是 xj。

然后给出 Q 个询问,第 k 个询问给出一个村庄的编号 yk,问该村庄距离最近的商店有多远?


输入格式

第一行包含两个整数 N,M。

接下来 M 行,每行包含三个整数 ai,bi,ci,表示第 i 条道路连接村庄 ai 和村庄 bi,长度是 ci。

再一行包含整数 K。

接下来 K 行,每行包含一个整数 xj,表示第 j 个有商店的村庄编号是 xj。

再一行包含整数 Q。

接下来 Q 行,每行包含一个整数 yk,表示询问编号为 yk 的村庄与其距离最近的商店之间的距离。


输出格式

对于每个询问,输出该询问的结果。


数据范围

2≤N≤105,N−1≤M≤min(N(N−1)/2,105),1≤Q≤105,1≤K≤N,1≤ci≤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、思路分析

思路来源:y总讲解视频

y总yyds

(1)将每个商店看做起点,在图中添加一个虚拟源点(起点),该点到其后面所有商店的距离均为0(有向边),则可以将从村庄走到商店的最短路径转化为从村庄走到源点(也就是从源点到村庄)的最短路径,两者等价。

(2)模拟上述过程,求从虚拟源点到村庄的最短路径,即为从村庄到商店的最短路径。


2、时间复杂度

时间复杂度为O(mlogn)(n表示点数,m表示边数)


3、代码详解

#include <iostream>

#include <queue>

#include <cstring>

#include <utility>

using namespace std;

typedef pair<int,int> PII;

const int N=100010,M=3*N;   //N代表点数,M代表边数,因需要为每个起点添加一条由虚拟源点指向的边,所以开成点数3倍

int dist[N];                //存储每个点到虚拟源点的最短路径

int h[N],e[M],w[M],ne[M],idx;   //h[]存储每个点第一条边的idx,e[]存储每条边的终点,ne[]存储每条边同起点的下一条边的idx,idx存储边的编号

bool st[N];

int n,m;

//邻接表中添加一条边

void add(int a,int b,int c){

   e[idx]=b;

   w[idx]=c;

   ne[idx]=h[a];

   h[a]=idx++;

}

//堆优化dijkstra求最短路

int dijkstra(){

   memset(dist,0x3f,sizeof dist);

   priority_queue<PII,vector<PII>,greater<PII>> heap;

   dist[0]=0;

   heap.push({0,0});

   while(!heap.empty()){

       PII t=heap.top();

       heap.pop();

       int ver=t.second;

       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});

           }

       }

   }

   if(dist[n]==0x3f3f3f3f) return -3;

   else return dist[n];

}

int main(){

   cin>>n>>m;

   memset(h,-1,sizeof h);

   while(m--){

       int a,b,c;

       cin>>a>>b>>c;

       add(a,b,c);

       add(b,a,c);

   }

   int k;

   cin>>k;

   while(k--){

       int x;

       cin>>x;

       add(0,x,0);      //添加一个虚拟源点到每个商店距离为0的有向边

   }

   dijkstra();

   int q;

   cin>>q;

   while(q--){

       int y;

       cin>>y;

       cout<<dist[y]<<endl;

   }

   return 0;

}

三、知识风暴

Dijkstra算法

基本思想:将一个带权有向图中的顶点分成两组,一组是未确定最短路的,一组是已确定最短路的。每次将未确定最短路集合中的点,按照与源点的距离递增加入已确定最短路的集合中,同时每次往已确定最短路集合中加入一个点后,需要用这个点来更新其他点距离源点的距离。当所有点的最短路都已确定,算法结束。


目录
相关文章
|
6月前
|
人工智能 算法 Java
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1005 数字游戏
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1005 数字游戏
109 0
|
6月前
|
Java C语言 C++
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1000 kAc给糖果你吃
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1000 kAc给糖果你吃
82 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-999 数的潜能
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-999 数的潜能
83 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-997 粘木棍
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-997 粘木棍
89 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1007 印章
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1007 印章
63 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1006 拿金币
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1006 拿金币
66 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1004 无聊的逗
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1004 无聊的逗
92 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1003 礼物
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1003 礼物
92 0
|
6月前
|
算法 Java C语言
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1001 跳马
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-1001 跳马
66 0
|
6月前
|
移动开发 算法 Java
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-998 娜神平衡
第十四届蓝桥杯集训——练习解题阶段(无序阶段)-ALGO-998 娜神平衡
59 0