提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这一道蓝桥杯的题用最短路径算法(迪杰斯特拉算法)是最好不过,无非就是在权的基础上加上;了隔离的时间,但完全可以看成一个东西。
一、题目描述
A 国有 N 个城市,编号为 1 . . . N。小明是编号为 1 的城市中一家公司的员工,今天突然接到了上级通知需要去编号为 N 的城市出差。
由于疫情原因,很多直达的交通方式暂时关闭,小明无法乘坐飞机直接从城市 1 到达城市 N,需要通过其他城市进行陆路交通中转。小明通过交通信息网,查询到了 M 条城市之间仍然还开通的路线信息以及每一条路线需要花费的时间。
同样由于疫情原因,小明到达一个城市后需要隔离观察一段时间才能离开该城市前往其他城市。通过网络,小明也查询到了各个城市的隔离信息。(由于小明之前在城市 1,因此可以直接离开城市 1,不需要隔离)
由于上级要求,小明希望能够尽快赶到城市 N,因此他求助于你,希望你能帮他规划一条路线,能够在最短时间内到达城市 N。
输入格式
第 1 行:两个正整数 N, M, N 表示 A 国的城市数量,M 表示未关闭的路线数量
第 2 行:N 个正整数,第 i 个整数 Ci 表示到达编号为 i 的城市后需要隔离的时间
第 3 . . . M + 2 行:每行 3 个正整数,u, v, c,表示有一条城市 u 到城市 v 的双向路线仍然开通着,通过该路线的时间为 c
输出格式
第 1 行:1 个正整数,表示小明从城市 1 出发到达城市 N 的最短时间(到达城市 N,不需要计算城市 N 的隔离时间)
样例输入
4 4
5 7 3 4
1 2 4
1 3 5
2 4 3
3 4 5
样例输出
13
提示
路线 1:1 -> 2 -> 4,时间为 4+7(隔离)+3=14
路线 2:1 -> 3 -> 4,时间为 5+3(隔离)+5=13
对于 100% 的数据,1 ≤ N ≤ 1000 , 1 ≤ M ≤ 10000, 1 ≤ Ci ≤ 200, 1 ≤ u, v ≤ N, 1 ≤ c ≤ 1000
二、迪杰斯特拉算法解析
1.为每个路径赋值
代码如下(示例):
scanf("%d%d%d",&u,&v,&c);
edge[u][v]=c+geli[v];
if(u==1){//进行dis比较赋值,这里考虑双向路径(即给的终点是起点)
dis[v]=min(dis[v],edge[u][v]);
}
edge[v][u]=c+geli[u];
if(v==1){
dis[u]=min(dis[u],edge[v][u]);
}
2.在迪杰斯特拉函数中找到未标记的最小路径
代码如下(示例):
vis[1]=true;//进行记录,标记“1”已经被标记,
int d=0x3f3f3f3f;//最大的int数
int t=-1;//便于置换
for(int i=1;i<=n;i++){//用来寻找最小的不被标记的带权值的路径
if(vis[i]!=true){
if(dis[i]<d){
dis[i]=min(dis[i],d);
t=i;
}
}
}
vis[t]=true;//将搜到的最短路径标记
3.将最小路径点标记后,遍历周围未标记路径,若小于更新后最小路径,则更新。
代码如下(示例):
for(int i=1;i<=n;i++){//遍历更新所标记点周围未标记点的路经
if(vis[i]!=true&&edge[t][i]!=0){
if(dis[t]+edge[t][i]<dis[i]){
dis[i]=min(dis[t]+edge[t][i],dis[i]);//若为最短路径的话,则dis[i]更新
}
}
}
4.总代码
#include <iostream>
#include <string.h> //#include <cstring> (不可用)
#include <math.h>
using namespace std;
int geli[1005];
int dis[1005];
int edge[1005][1005];
bool vis[10005];
int n,m;
int dijkstra(){
vis[1]=true;//进行记录,标记“1”已经被标记,
for(int j=1;j<=n;j++){//这个循环是为了标记所有城市
int d=0x3f3f3f3f;//最大的int数
int t=-1;//便于置换
for(int i=1;i<=n;i++){//用来寻找最小的不被标记的带权值的路径
if(vis[i]!=true){
if(dis[i]<d){
dis[i]=min(dis[i],d);
t=i;
}
}
}
vis[t]=true;//将搜到的最短路径标记
for(int i=1;i<=n;i++){//遍历更新所标记点周围未标记点的路经
if(vis[i]!=true&&edge[t][i]!=0){
if(dis[t]+edge[t][i]<dis[i]){
dis[i]=min(dis[t]+edge[t][i],dis[i]);//若为最短路径的话,则dis[i]更新
}
}
}
}
return dis[n];//最后将得到到末尾的最短函数
}
int main(){
int u,v,c;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&geli[i]);
}
geli[n]=0;
memset(dis,0x3f,sizeof(dis));//将dis【i】设为无穷大,好进行min
for(int i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&c);
edge[u][v]=c+geli[v];
if(u==1){//进行dis比较赋值,这里考虑双向路径(即给的终点是起点)
dis[v]=min(dis[v],edge[u][v]);
}
edge[v][u]=c+geli[u];
if(v==1){
dis[u]=min(dis[u],edge[v][u]);
}
}
dijkstra();
printf("%d",dis[n]);
return 0;
}
总结
这一道蓝桥杯出差题,真的是一道非常好的锻炼自己写迪杰斯特拉算法的一道编程题,如果用迪杰斯特拉算法的话,几乎没有任何难度