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

最新文章

  1. yii学习笔记
  2. 【mysql】压缩myisam数据表
  3. Oracle中synonym和index
  4. android Material Design:主题
  5. LightOJ 1074 Extended Traffic SPFA 消负环
  6. 2014第7周三初识CouchBase
  7. latex如何把目录页的页码去掉?
  8. Haproxy------在windows下配置负载均衡
  9. Solr 10 - SolrCloud集群模式简介 + 组成结构的说明
  10. luogu P4842 城市旅行
  11. codeforces 1017C - Cloud Computing 权值线段树 差分 贪心
  12. Fiddler2如何对Android应用进行抓包
  13. nodejs内存溢出解决方法
  14. 查询SQLSERVER执行过的SQL记录(测试通过)
  15. idea debug info can be unavailable. Please close other application using ADB: Monitor, DDMS, Eclipse
  16. 对SQL语句进行过滤的函数
  17. 转 UIAlertView 不显示、屏幕变灰
  18. 使用用户自定义类型作为map的key
  19. 92. Reverse Linked List II(链表部分反转)
  20. java 的异常处理

热门文章

  1. 使用 FairyGUI 0代码实现游戏界面左右切换
  2. TCP、三次握手、四次挥手(图解)
  3. layui增加转圈效果
  4. 网络管理之命令行工具nmcli
  5. P7708「Wdsr-2.7」八云蓝自动机 Ⅰ
  6. Oracle-除了会排序,你对ORDER BY的用法可能一无所知!
  7. php背景透明png
  8. 修改unittest源码之tearDown
  9. Java8 Lambda表达式、函数式接口和方法引用
  10. MapReduce01 概述