题面

Link

题目背景

小X来到了山区,领略山林之乐。在他乐以忘忧之时,他突然发现,开学迫在眉睫

题目描述

山区有 \(n\) 座山。山之间有 \(m\) 条羊肠小道,每条连接两座山,只能单向通过,并会耗费小X一定时间。

小X现在在 \(1\) 号山,他的目的是 \(n\) 号山,因为那里有火车站。

然而小X的体力是有限的。他每通过一条羊肠小道,就会变得更疲劳,导致他通过任意一条羊肠小道的时间都增加 \(1\)。

输入格式

第一行两个数,\(n\),\(m\)

第 \(2\) 行到第 \(m+1\) 行,每行 \(3\) 个数 \(A\),\(B\),\(C\),表示 \(A\)、\(B\) 之间有一条羊肠小道,可以让小X花费 \(C\) 的时间从 \(A\) 移动到 \(B\)

输出格式

两行 第一行一个数 \(T\),表示小X需要的最短时间

第二行若干个数,用空格隔开,表示小X的移动路线

例:1 4 2 5表示:小X从1号山开始,移动到4号山,再到2号山,最后到5号山。

输入输出样例

输入 #1

5 8

2 4 2

5 2 1

1 2 1

4 3 2

1 3 3

4 5 2

1 5 8

3 5 3

输出 #1

7

1 3 5

说明/提示

n<=10000, m<=200000

数据保证没有多条最短路径

题解

本来以为这道题是道水题,能一遍过的。

结果没想到,这道题太过毒瘤,导致我交了好几遍(雾)

我们的正常思路就是 记录到每个点经过的的边的数量

转移距离时算上 f[t] 来进行更新 。

在从一跑一遍最短路,统计答案就记一下每个点的前驱,就完事了。

核心代码长这样


void spfa()
{
queue<int> q;
memset(dis,127,sizeof(dis));//dis初值设为极大值
q.push(1); dis[1] = 0; vis[1] = 1;
while(!q.empty())
{
int t = q.front(); q.pop(); vis[t] = 0;
for(int i = head[t]; i; i = e[i].net)
{
int to = e[i].to;
int tmp = f[t] + 1;
if(dis[to] > dis[t] + e[i].w + f[t])//算上累计的疲劳度
{
dis[to] = dis[t] + e[i].w + f[t];
f[to] = f[t] + 1;//更新一下 f[to]
pre[to] = t;//记录前驱
if(!vis[to])
{
q.push(to);
vis[to] = 1;
}
}
}
}
}

当你满怀信心交上去时,却发现最后两个点 WA 了。

我想了想,看了看别人的帖子,发现有一组 hack 数据

hack1:
INPUT:
7 7
1 2 2
2 3 2
3 4 2
4 5 2
5 6 2
6 7 2
1 4 10
OUTPUT:
22
1 4 5 6 7 hack2:
INPUT:
7 7
1 2 1
2 3 1
3 4 1
4 5 1
5 6 1
6 7 1
1 5 14
OUTPUT:
19
1 5 6 7

我们把这张图画下来,他张这样

我们问题主要出现在 1-2-3-4-5-6-7 和 1-4-5-6-7 这两条路径,他们的路径长度相同。

但正解却是路径二,因为路径二的疲劳值比 一小。

按照我们正常的做法就会被 HACK 掉。

那我们怎么解决这个问题呢?

这就要用到一个玄学的做法,建反图倒着跑最短路。

证明一下:

假设我们有两条路径 1-2-3-4-5-6-7 和 1-4-5-6-7

当我们更新到 4 的时候,有两条路 到三或者直接到 一。

我们反着跑最短路就会先更新 一,这就避免了上面的那种情况。

这就相当于我们能到终点就直接到终点,而不是走弯路。

Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int N = 1e5+10;
int n,m,tot,u,v,w,cnt;
int head[N],dis[N],f[N],pre[N],a[N];
bool vis[N];
struct node
{
int to,net,w;
}e[200010];
inline int read()
{
int s = 0,w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
return s * w;
}
void add(int x,int y,int w)
{
e[++tot].w = w;
e[tot].to = y;
e[tot].net = head[x];
head[x] = tot;
}
void spfa()
{
queue<int> q;
memset(dis,127,sizeof(dis));
q.push(n); dis[n] = 0; vis[n] = 1;
while(!q.empty())
{
int t = q.front(); q.pop(); vis[t] = 0;
for(int i = head[t]; i; i = e[i].net)
{
int to = e[i].to;
int tmp = f[t] + 1;
if(dis[to] > dis[t] + e[i].w + f[t])
{
dis[to] = dis[t] + e[i].w + f[t];
f[to] = f[t] + 1;
pre[to] = t;
if(!vis[to])
{
q.push(to);
vis[to] = 1;
}
}
}
}
}
int main()
{
n = read(); m = read();
for(int i = 1; i <= m; i++)
{
u = read(); v = read(); w = read();
add(v,u,w);///建反图跑最短路
}
spfa();
printf("%d\n",dis[1]);
int x = 1;
while(x != n)
{
a[++cnt] = x;
x = pre[x];
}
a[++cnt] = n;
for(int i = 1; i <= cnt; i++)//输出路径
{
printf("%d ",a[i]);
}
return 0;
}

P2832 行路难的更多相关文章

  1. 洛谷P2832 行路难 分析+题解代码【玄学最短路】

    洛谷P2832 行路难 分析+题解代码[玄学最短路] 题目背景: 小X来到了山区,领略山林之乐.在他乐以忘忧之时,他突然发现,开学迫在眉睫 题目描述: 山区有n座山.山之间有m条羊肠小道,每条连接两座 ...

  2. 洛谷 P2832 行路难

    题面 这个最短路有点special,会有疲劳度的加成效应,这个时候应该怎么办呢? 难就难在,如果走一条路比另一条路长,但是用的边少,那么这条路并不一定就更差. 我们要是能解决这个问题,就可以做出本题. ...

  3. SPFA+寻路(行路难,洛谷2832)

    啊啊啊这道难题总算是做出来了,首先是帅比浮云的题解发出来一下:http://www.cnblogs.com/fuyun-boy/p/5922742.html 原题目地址:https://www.luo ...

  4. [CODEVS2603]公路修建

    题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成.    修建工程分若干轮完成.在每一轮中,每个城市选 ...

  5. Netty4 学习笔记之三:粘包和拆包

    前言 在上一篇Netty 心跳 demo 中,了解了Netty中的客户端和服务端之间的心跳.这篇就来讲讲Netty中的粘包和拆包以及相应的处理. 名词解释 粘包: 会将消息粘粘起来发送.类似吃米饭,一 ...

  6. P1265 公路修建 最小生成树

    题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成. 修建工程分若干轮完成.在每一轮中,每个城市选择一个 ...

  7. HTML标记语言

    一.html的文档结构 html含义为超文本标记语言,html文档重要由4个标签来组成就是<html>  <head>  <title>  <body> ...

  8. 洛谷P1265 公路修建(Prim)

    To 洛谷.1265 公路修建 题目描述 某国有n个城市,它们互相之间没有公路相通,因此交通十分不便.为解决这一“行路难”的问题,政府决定修建公路.修建公路的任务由各城市共同完成. 修建工程分若干轮完 ...

  9. 洛谷P1265 公路修建

    P1265 公路修建 177通过 600提交 题目提供者该用户不存在 标签图论 难度普及+/提高 提交该题 讨论 题解 记录 最新讨论 long long类型赋值-1为什么… p党80的进 为什么不过 ...

随机推荐

  1. 《神经网络的梯度推导与代码验证》之CNN前向和反向传播过程的代码验证

    在<神经网络的梯度推导与代码验证>之CNN的前向传播和反向梯度推导 中,我们学习了CNN的前向传播和反向梯度求导,但知识仍停留在纸面.本篇章将基于深度学习框架tensorflow验证我们所 ...

  2. [第二届全国中学生网络安全竞赛]bypass

    前几天拿到了线下赛的源码,做做看.这道主要是命令执行的黑名单绕过 先看看给出的代码: <?php highlight_file(__FILE__); error_reporting(0); $b ...

  3. Java进阶专题(十三) 从电商系统角度研究多线程(上)

    前言 ​ 本章节主要分享下,多线程并发在电商系统下的应用.主要从以下几个方面深入:线程相关的基础理论和工具.多线程程序下的性能调优和电商场景下多线程的使用. 多线程J·U·C 线程池 概念 回顾线程创 ...

  4. 写给.NET开发者的Python教程(三):运算符、条件判断和循环语句

    本节会介绍Python中运算符的用法,以及条件判断和循环语句的使用方法. 运算符 运算符包括算术运算符.赋值运算符.比较运算符.逻辑运算符等内容,大部分用法和C#基本一致,下面我们来看一下: 算数运算 ...

  5. 20190928-02使用Redis客户端Jedis连接Redis,以及用Java代码操作Redis 000 030

    启动redis package com.yujie.jedis; import java.util.HashMap; import java.util.Map; import java.util.Se ...

  6. leetcode刷题-89格雷编码

    题目 格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异. 给定一个代表编码总位数的非负整数 n,打印其格雷编码序列.即使有多个不同答案,你也只需要返回其中一种. 格雷编码序列 ...

  7. 11.QT-ffmpeg+QAudioOutput实现音频播放器

    1.前言      由于QAudioOutput支持的输入数据必须是原始数据,所以播放mp3,WAV,AAC等格式文件,需要解封装后才能支持播放.      而在QT中,提供了QMediaPlayer ...

  8. 一起来读官方文档-----SpringIOC(04)

    1.4.2.依赖性和详细配置 如上一节所述,您可以将bean属性和构造函数参数定义为对其他托管bean(协作者)的引用或内联定义的值.Spring的基于XML的配置元数据为此目的在其和元素中支持子元素 ...

  9. 浅说iOS二维码的那些事儿

    二维码需要用到 Quartz 2D 一般是三步走~1导入CoreImage框架,编写字符串转二维码图;2渲染二维码;3显示二维码. 导入头文件 #import <CoreImage/CoreIm ...

  10. 集群数据ID生成之美团叶子生成

    转自https://tech.meituan.com/2017/04/21/mt-leaf.html 在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识.如在美团点评的金融.支付.餐饮.酒店. ...