CF20C Dijkstra? 题解
Content
给定一张 \(n\) 个点 \(m\) 条边的无向图,请判断是否有一条可行的从 \(1\) 到 \(n\) 的路径,有的话输出长度最短的,没有的话输出 -1。
数据范围:\(2\leqslant n\leqslant 10^5\),\(0\leqslant m\leqslant 10^5\),每条边的长度不超过 \(10^6\)。
Solution
这道题的标题当中看上去是在误导你不用 \(\textsf{Dijkstra}\),其实已经给出了这道题目的做法就是:\(\textsf{Dijkstra}\)。为了优化复杂度,我用了堆优化 + \(\textsf{Dijkstra}\)。
那么 \(\textsf{Dijkstra}\) 如何做到能够输出路径呢?这里我们就需要用到一个 \(\textit{pre}\) 数组,其中 \(\textit{pre}_i\) 表示最短路径中在 \(i\) 点前面的点。我们可以在 \(\textsf{Dijkstra}\) 处理 \(\textit{dis}\) 数组的时候就把这个 \(pre\) 更新一遍,就像这样:
for(int i = h[x]; i; i = e[i].nxt) {
int y = e[i].to, z = e[i].v;
if(dis[y] > dis[x] + z) { //更新最短路
dis[y] = dis[x] + z, pre[y] = x; //更新最短路的长度和当前点在最短路上的前一个节点。
q.push(make_pair(-dis[y], y));
}
}
那么我们又如何判断是否存在从 \(1\) 到 \(n\) 最短路径呢?这里给出两种方法:
第一种,还记得我们在跑 \(\textsf{Dijkstra}\) 的时候要先做什么吗?没错,初始化 \(\textit{dis}\) 数组。由于是最短路,我们需要将这个 \(\textit{dis}\) 数组的初值设得尽可能大,又因为在数据范围中我们发现:
\(0\leqslant m\leqslant 10^5\),每条边的长度不超过 \(10^6\)。
所以我们就知道了,可能最长的最短路长度为 \(10^5\times 10^6=10^{11}\),因此我们需要开 long long,并将这个 \(\textit{dis}\) 数组赋初值赋在 \(10^{11}\) 以上,下面这一段以笔者在代码中赋的初值 \(10^{18}\) 为准。
然后我们就可以通过这个来判断是否存在到 \(n\) 的最短路径了:只需要判断是否有 \(\textit{dis}_n\neq10^{18}\) 即可,因为如果 \(\textit{dis}_n=10^{18}\),那么就说明 \(\textit{dis}_n\) 还从来没有更新过,自然也就不存在从 \(1\) 到 \(n\) 的最短路径了。
第二种,就要用到这一题中所引入的 \(\textit{pre}\) 数组了,我们可以从 \(n\) 开始,直接利用 \(x\leftarrow\textit{pre}_x\) 向前推最短路径上的节点,看是否能够推到 \(1\),如果最终不能够推到 \(1\) 就说明不存在从 \(1\) 到 \(n\) 的最短路径。
两种方法虽然看上去第一种的表述要多一些,但实际上这两种方法的实现程度都是不难的,因此推荐大家把两种写法都写一遍。
另外,我们也可以从这道题目中吸取一些教训:标题并不一定就决定了你的做题思路,你的做题思路应当从题面中通过思考而得出。
Code 1
const int N = 1e5 + 7, M = N << 1;
int n, m, u, v, w, cnt, fl, vis[N], h[M], ans[N], pre[N];
ll dis[N];
struct edge {int v, to, nxt;}e[M];
pq<pair<ll, int> > q;
iv a_e(int u, int v, int w) {e[++cnt] = (edge){w, v, h[u]}; h[u] = cnt;}
iv dj() {
F(i, 1, 100000) dis[i] = 1e18;
dis[1] = 0, q.push(mp(0, 1));
while(!q.empty()) {
int x = q.top().se; q.pop();
if(vis[x]) continue; vis[x] = 1;
E {
int y = e[i].to, z = e[i].v;
if(dis[y] > dis[x] + z) {
dis[y] = dis[x] + z, pre[y] = x;
q.push(mp(-dis[y], y));
}
}
}
}
int main() {
n = Rint, m = Rint;
F(i, 1, m) {
u = Rint, v = Rint, w = Rint;
a_e(u, v, w), a_e(v, u, w);
}
dj();
for(int cur = n; cur; cur = pre[cur]) ans[++ans[0]] = cur;
if(dis[n] != (ll)1e18) R(i, ans[0], 1) write(ans[i]), putchar(" \n"[i == n]);
else puts("-1");
return 0;
}
Code 2
const int N = 1e5 + 7, M = N << 1;
int n, m, u, v, w, cnt, fl, vis[N], h[M], ans[N], pre[N];
ll dis[N];
struct edge {int v, to, nxt;}e[M];
pq<pair<ll, int> > q;
iv a_e(int u, int v, int w) {e[++cnt] = (edge){w, v, h[u]}; h[u] = cnt;}
iv dj() {
F(i, 1, 100000) dis[i] = 1e18;
dis[1] = 0, q.push(mp(0, 1));
while(!q.empty()) {
int x = q.top().se; q.pop();
if(vis[x]) continue; vis[x] = 1;
E {
int y = e[i].to, z = e[i].v;
if(dis[y] > dis[x] + z) {
dis[y] = dis[x] + z, pre[y] = x;
q.push(mp(-dis[y], y));
}
}
}
}
int main() {
n = Rint, m = Rint;
F(i, 1, m) {
u = Rint, v = Rint, w = Rint;
a_e(u, v, w), a_e(v, u, w);
}
dj();
for(int cur = n; cur; cur = pre[cur]) {
ans[++ans[0]] = cur;
if(cur == 1) fl = 1;
}
if(fl) R(i, ans[0], 1) write(ans[i]), putchar(" \n"[i == n]);
else puts("-1");
return 0;
}
CF20C Dijkstra? 题解的更多相关文章
- 【算法】祭奠spfa 最短路算法dijspfa
题目链接 本题解来源 其他链接 卡spfa的数据组 题解堆优化的dijkstra 题解spfa讲解 来自以上题解的图片来自常暗踏阴 使用前向星链表存图 直接用队列优化spfa struct cmp { ...
- 【GDOI2018】所有题目和解题报告
使用说明:题意和数据范围都只是回忆内容,仅供参考.题解陆续补上. Day 1 第一题 题意:给定n个数字,要求划分成k的连续段使得每个连续段内的数字之和相同,求最大的k.n,Σai<=10^6. ...
- SCU-4527 NightMare2(Dijkstra+BFS) !!!错误题解!!!
错解警告!!! 描述 可怜的RunningPhoton又做噩梦了..但是这次跟上次不大一样,虽然他又被困在迷宫里,又被装上了一个定时炸弹,但是值得高兴的是,他发现他身边有数不清的财宝,所以他如果能带着 ...
- Newcoder Metropolis(多源最短路 + Dijkstra堆优化)题解
题目链接:https://www.nowcoder.com/acm/contest/203/I?tdsourcetag=s_pcqq_aiomsg来源:牛客网 思路:我们用用fa[i]表示距离i最近的 ...
- PAT甲题题解-1072. Gas Station (30)-dijkstra最短路
题意:从m个加油站里面选取1个站点,使得其离住宅的最近距离mindis尽可能地远,并且离所有住宅的距离都在服务范围ds之内.如果有很多相同mindis的加油站,输出距所有住宅平均距离最小的那个.如果平 ...
- PAT甲题题解-1111. Online Map (30)-PAT甲级真题(模板题,两次Dijkstra,同时记下最短路径)
题意:给了图,以及s和t,让你求s到t花费的最短路程.最短时间,以及输出对应的路径. 对于最短路程,如果路程一样,输出时间最少的. 对于最短时间,如果时间一样,输出节点数最少的. 如果最短路程 ...
- POJ 1797 Heavy Transportation(最短路&Dijkstra变体)题解
题意:给你所有道路的载重,找出从1走到n的所有路径中载重最大的,即路径最小值的最大值. 思路:和之前的POJ3268很像.我们用Dijkstra,在每次查找时,我们把最大的先拿出来,因为最大的不影响最 ...
- POJ 3268 Silver Cow Party(最短路&Dijkstra)题解
题意:有n个地点,有m条路,问从所有点走到指定点x再走回去的最短路中的最长路径 思路:用Floyd超时的,这里用的Dijkstra. Dijkstra感觉和Prim和Kruskal的思路很像啊.我们把 ...
- 【CF20C】Dijkstra?(DIJKSTRA+HEAP)
没什么可以说的 做dijk+heap模板吧 以后考试时候看情况选择SFPA和DIJKSTRA ; ..]of longint; dis:..]of int64; a:..]of int64; b:.. ...
随机推荐
- java实现自动化发布平台核心代码
1.搭建jenkins环境 (1)jenkins官网下载jenkins.war包 (2)将该war包放入到tomcat的webapp的目录下(前提条件需要配置tomcat的环境,详情请自行百度) (3 ...
- JVM的Xms Xmx PermSize MaxPermSize区别
Eclipse崩溃,错误提示:MyEclipse has detected that less than 5% of the 64MB of Perm Gen (Non-heap memory) sp ...
- 强化学习之MountainCarContinuous(注册自己的gym环境)
目录 1. 问题概述 2. 环境 2.1 Observation & state 2.2 Actions 2.3 Reward 2.4 初始状态 2.5 终止状态- Episode Termi ...
- 41-Climbing Stairs-leetcode
Climbing Stairs My Submissions QuestionEditorial Solution Total Accepted: 106498 Total Submissions: ...
- C语言大小端判定
要判定大小端?需要弄清以下几个问题: 1.当一个变量占多个字节时,变量的指针指向的是低地址 2.什么是大小端? 大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中. 小 ...
- 商业爬虫学习笔记day1
day1 一. HTTP 1.介绍: https://www.cnblogs.com/vamei/archive/2013/05/11/3069788.html http://blog.csdn.ne ...
- Linux学习 - 输入输出重定向,管道符,通配符
一.键盘输入读取read read [选项] [变量名] -p [显示信息] 在等待read输入时,输出提示信息 -t [秒数] 指定read输入等待时间 -n [字符数] 指定read只接收n个字符 ...
- rust常用技巧
允许未使用的方法,写在文件开头,可过滤过掉该项提示 #![allow(unused)]
- ORACLE 获取执行计划的方法
一.获取执行计划的6种方法(详细步骤已经在每个例子的开头注释部分说明了): 1. explain plan for获取: 2. set autotrace on : 3. statistics_lev ...
- JAVA序列化浅析
java.io.Serializable浅析 Java API中java.io.Serializable接口源码: 1 public interface Serializable { 2 } 类通过实 ...