news 2026/4/17 23:14:20

城市路(Dijkstra)(信息学奥赛一本通- P1381)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
城市路(Dijkstra)(信息学奥赛一本通- P1381)

【题目描述】

罗老师被邀请参加一个舞会,是在城市n,而罗老师当前所处的城市为1,附近还有很多城市2∼n−1,有些城市之间没有直接相连的路,有些城市之间有直接相连的路,这些路都是双向的,当然也可能有多条。

现在给出直接相邻城市的路长度,罗老师想知道从城市1到城市n,最短多少距离。

【输入】

输入n, m,表示n个城市和m条路;

接下来m行,每行abc, 表示城市a与城市b有长度为c的路。

【输出】

输出1到n的最短路。如果1到达不了n,就输出−1。

【输入样例】

5 5 1 2 20 2 3 30 3 4 20 4 5 20 1 5 100

【输出样例】

90

【提示】

【数据规模和约定】

1≤n≤2000

1≤m≤10000

0≤c≤10000

0. 题目速览

题意:给定N个点M条边的无向正权图,求点1到点N的最短距离。不可达输出 -1。

数据:N<=2000,M<=10000。

1. 核心难点与算法选型

做题时,首先分析数据量,面对N=2000的数据,选择错误的算法直接导致tle

算法复杂度计算量预估判决评价
FloydO(N^3)8*10^9必挂只能跑N<=300。80亿次运算需要几十秒。
Bellman-FordO(N*M)4*10^7勉强过效率一般,若N再大一点就会超时。
SPFAAvg O(k* M)约2*10^5AC平均极快,但最坏情况退化为O(N*M)。正权图不建议作为首选
Dijkstra (堆优化)O(M log N)约 2*10^5完美 AC正权图首选,最稳定,无视数据构造。

结论:本题最佳方案为Dijkstra(堆优化)

2. 易错点

  1. 无向图陷阱

    • 题目是双向路,存图时必须建两条边addedge(u, v, w)addedge(v, u, w)

    • 如果是邻接矩阵(Floyd),记得g[u][v] = g[v][u] = min(...)

  2. 头文件

    • 使用memset建议加<cstring>

    • 使用min/max建议加<algorithm>

    • 注:这是比赛中最常见的 CE 原因。

  3. 不可达判断

    • 初始化disINF(如0x3f3f3f3f)。

    • 输出前检查if (dis[n] == 0x3f3f3f3f) cout << -1;

3. 完整代码

//n是2*10^3量级,此题最佳还是Dijkstra 但我也写个spfa和floyd做个示范 /* //第一种 Dijkstra #include <iostream> #include <queue> #include <cstring> using namespace std; const int maxn=2100; const int maxm=21000; int n,m; int h[maxn]; int vtex[maxm]; int nxt[maxm]; int wt[maxm]; int idx; int dis[maxn];//每个城市到1号城市到最短距离 int vis[maxn]; struct node{ int id;//每个城市编号 int w;//每个城市到一号城市的最短距离 //优先队列默认大根堆,重载运算符变为小根堆 friend bool operator <(node a,node b){ return a.w>b.w; } }; priority_queue<node> q; void dijkstra(int s){ dis[s]=0;//起点到自己距离为0 node tmp; tmp.id=s; tmp.w=0;//记录这个才能确保每次出队都是离1号城市距离最近的城市 q.push(tmp);//源点入队 while(!q.empty()){ tmp=q.top();//访问队首元素 q.pop();//队首出队 int nid=tmp.id;//当前出队城市编号 if(vis[nid]==1) continue;//如果tmp已经出队过,就直接跳过 vis[nid]=1;//否则就打上出队标记 int p=h[nid];//记录tmp头指针 while(p!=-1){//遍历tmp所有邻接点 if(vis[vtex[p]]==0){//如果该邻接点没有出队过 //如果该邻接点到1号城市距离大于 tmp到1号城市距离+边权 //就更新该邻接点到1号城市距离并入队 if(dis[vtex[p]]>dis[nid]+wt[p]){ dis[vtex[p]]=dis[nid]+wt[p]; q.push({vtex[p],dis[vtex[p]]}); } } p=nxt[p];//更新指针 } } } void addedge(int u,int v,int w){ vtex[idx]=v; nxt[idx]=h[u]; wt[idx]=w; h[u]=idx++; } int main(){ cin>>n>>m; memset(h,-1,sizeof(h));//初始化头指针数组 //邻接表存图 for(int i=1;i<=m;i++){ int u,v,w; cin>>u>>v>>w; addedge(u,v,w);//双向道路 addedge(v,u,w); } for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;//初始化最短距离为无穷 dijkstra(1); if(dis[n]==0x3f3f3f3f) cout<<-1; else cout<<dis[n]; return 0; } */ /* //floyd #include <iostream> #include <cstring> #include <algorithm> using namespace std; int n,m; int g[2100][2100]; void floyd(){ for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ g[i][j]=min(g[i][j],g[i][k]+g[k][j]); } } } } int main(){ cin>>n>>m; //初始化邻接矩阵内所有城市间距离为无穷 for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ g[i][j]=0x3f3f3f3f; } } for(int i=1;i<=n;i++) g[i][i]=0;//所有城市自己到自己距离为0; //邻接矩阵存图 for(int i=1;i<=m;i++){ int u,v,w; cin>>u>>v>>w; //防止两个城市间有多条重复边,但是边距离不同 g[u][v]=g[v][u]=min(g[u][v],w); } floyd(); if(g[1][n]==0x3f3f3f3f) cout<<-1; else cout<<g[1][n]; return 0; } */ /* //spfa #include <iostream> #include <cstring> #include <queue> using namespace std; queue<int> q; const int maxn=2100; const int maxm=21000; int n,m; int h[maxn]; int vtex[maxm]; int nxt[maxm]; int wt[maxm]; int idx; int dis[maxn];//每个城市到1号城市到最短距离 bool is_used[maxn];//记录每个城市是否在队列中 void spfa(int s){ int tmp=s; dis[tmp]=0;//源点到自己距离为0 q.push(tmp);//源点入队 is_used[tmp]=1;//打上标记 while(!q.empty()){ tmp=q.front();//访问队首元素 q.pop();//队首出队 is_used[tmp]=0;//出队后就取消标记 int p=h[tmp];//tmp的头指针 while(p!=-1){//遍历tmp的所有邻接点 //如果该邻接点到源点到距离大于 tmp到源点的距离+边权 if(dis[vtex[p]]>dis[tmp]+wt[p]){ //更新该邻接点到源点到距离 dis[vtex[p]]=dis[tmp]+wt[p]; //判断该邻接点是否已经在队列中,不在就打上标记并入队 //在就不用入队了,因为后面迟早要出队的 if(is_used[vtex[p]]==0){ is_used[vtex[p]]=1; q.push(vtex[p]); } } p=nxt[p];//更新指针; } } } void addedge(int u,int v,int w){ vtex[idx]=v; nxt[idx]=h[u]; wt[idx]=w; h[u]=idx++; } int main(){ cin>>n>>m; memset(h,-1,sizeof(h));//初始化头指针数组 //邻接表存图 for(int i=1;i<=m;i++){ int u,v,w; cin>>u>>v>>w; addedge(u,v,w);//双向道路 addedge(v,u,w); } for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;//初始化所有点到dis的距离为无穷 spfa(1); if(dis[n]==0x3f3f3f3f) cout<<-1; else cout<<dis[n]; return 0; } */ //bellman-ford #include <iostream> using namespace std; int n,m; struct edge{ int u; int v; int w; }e[21000];//存所有边 int dis[2100]; void ford(int s){ dis[s]=0;//起点到自己距离为0 for(int i=1;i<n;i++){//迭代n-1次 bool flag=0;//标记这一整轮是否发生更新 for(int j=1;j<=2*m;j++){//双向道路,所以是2*m条 //如果一条边终点到源点距离大于 边起点到源点距离+边权 就更新边终点到源点距离 if(dis[e[j].v]>dis[e[j].u]+e[j].w){ dis[e[j].v]=dis[e[j].u]+e[j].w; flag=1;//并更新标记 } } if(flag==0) break;//当一整轮都没有发生更新,就退出 } } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) dis[i]=0x3f3f3f3f;//初始化每个点到源点距离为0 for(int i=1;i<=m;i++){ int a,b,c; cin>>a>>b>>c; e[i].u=e[i+m].v=a;//双向边 e[i].v=e[i+m].u=b; e[i].w=e[i+m].w=c; } ford(1); if(dis[n]==0x3f3f3f3f) cout<<-1; else cout<<dis[n]; return 0; }

4. 笔记:SPFA vs Bellman-Ford

很多同学纠结于负权边算法的选择,这里统一总结:

  • 正权图:无脑选Dijkstra

  • 负权图 (无负环):首选SPFA。它是 Bellman-Ford 的队列优化版,平均效率高出几十倍。

  • 什么时候用 Bellman-Ford?

    1. 题目限制路径最多经过k条边

    2. 图极其稠密或特殊构造,导致 SPFA 退化严重(极罕见)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 8:40:50

Anki记忆神器:科学间隔重复助你轻松掌握海量知识 [特殊字符]

Anki记忆神器&#xff1a;科学间隔重复助你轻松掌握海量知识 &#x1f4da; 【免费下载链接】anki Ankis shared backend and web components, and the Qt frontend 项目地址: https://gitcode.com/GitHub_Trending/an/anki 在信息爆炸的时代&#xff0c;高效记忆成为每…

作者头像 李华
网站建设 2026/4/18 5:31:54

Unity包解压终极指南:无需Unity编辑器的一键提取方案

Unity包解压终极指南&#xff1a;无需Unity编辑器的一键提取方案 【免费下载链接】unitypackage_extractor Extract a .unitypackage, with or without Python 项目地址: https://gitcode.com/gh_mirrors/un/unitypackage_extractor unitypackage_extractor是一款专为Un…

作者头像 李华
网站建设 2026/4/18 5:34:58

翻译服务测试覆盖:单元测试与集成测试策略

翻译服务测试覆盖&#xff1a;单元测试与集成测试策略 &#x1f4cc; 引言&#xff1a;为何翻译服务需要完善的测试体系&#xff1f; 随着AI技术在自然语言处理领域的广泛应用&#xff0c;智能中英翻译服务已成为跨语言沟通的核心工具。尤其在轻量级、CPU部署的场景下&#xff…

作者头像 李华
网站建设 2026/4/18 4:03:04

Blender到Unity模型转换:告别坐标混乱的艺术

Blender到Unity模型转换&#xff1a;告别坐标混乱的艺术 【免费下载链接】blender-to-unity-fbx-exporter FBX exporter addon for Blender compatible with Unitys coordinate and scaling system. 项目地址: https://gitcode.com/gh_mirrors/bl/blender-to-unity-fbx-expor…

作者头像 李华
网站建设 2026/4/18 8:24:56

java springboot基于微信小程序的宠物医院宠物领养系统宠物商城(源码+文档+运行视频+讲解视频)

文章目录 系列文章目录目的前言一、详细视频演示二、项目部分实现截图三、技术栈 后端框架springboot前端框架vue持久层框架MyBaitsPlus微信小程序介绍系统测试 四、代码参考 源码获取 目的 摘要&#xff1a;本文设计并实现了一个基于Java SpringBoot框架与微信小程序的宠物综…

作者头像 李华
网站建设 2026/4/15 20:23:09

CSANMT模型安全审计:防范敏感信息泄露的配置指南

CSANMT模型安全审计&#xff1a;防范敏感信息泄露的配置指南 &#x1f4d6; 项目简介与安全背景 随着AI翻译服务在企业协作、跨境沟通和内容本地化中的广泛应用&#xff0c;CSANMT&#xff08;Conditional Self-Attentive Neural Machine Translation&#xff09; 模型凭借其高…

作者头像 李华