发现 \(K\) 很小,不妨设置一个 \(O(NK)\) 的 \(DP\)。

发现可行的最短路必须满足是 \(d <= dis <= d + K\)。

由逆向思维,则是从某点出发,可以消耗 \(K\) 个单位的冗余长度,最终到达 \(n\)。

如何快速的计算出有走这条边冗余长度呢

首先建反向图跑 \(Dijkstra\),求出 \(dis[i]\) 表示从 \(i\) 到 \(n\) 的最短路距离。

假设有一条边 \((u, v)\),边长为 \(w\)

那么我现在从 \(u\) 到 \(n\) 的预算距离是 \(dis[v] + w\),最短距离是 \(dis[u]\)。

那么多走的就是 \(dis[v] + w - dis[u]\)。

设计 \(DP\) 状态表示:

\(f[i][j]\) 表示从 \(i\) 到 \(n\),以及消耗了 \(j\) 个单位的冗余长度的方案数。

状态转移:

设有边 \((u, v)\),边长为 \(w\)

则有 \(f[u][j] += f[v][j - (dis[v] + w - dis[u])]\)。

边界 \(f[n][0] = 1\),其余为 \(0\)。

答案 \(\sum_{i = 0}^{K} f[1][i]\)。

无穷解的判断:

发现有无穷解,当且仅当:

有一个总权为 \(0\) 的环。

我们可以在 \(DP\) 的时候搞一个 \(vis\) 数组判断,就不需要单独判无穷解了。

时间复杂度

整个过程用记忆化搜索实现,由于一共有 \(NK\) 个状态,每个点被枚举 \(K\) 次,即每条边总体被枚举 \(K\) 次。

所以复杂度 \(O(K(N + M))\)。

\(Tips:\)

  1. 可能走到 \(n\) 再折回去,所以 $u = n $ 时不能直接 \(return\)
  2. 可能存在经过 \(n\) 点的 \(0\) 环,所以到 \(n\) 点时顺便判一下环。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <cstdlib>
using namespace std;
typedef pair<int, int> PII;
const int N = 100005, M = 400005, S = 51;
int n, m, K, P, f[N][S], dis[N];
int head[N], rhead[N], numE[2];
bool st[N], vis[N][S], ep = false;
struct E {
int next, v, w;
}e[M], r[M];
//建图
void inline add(E g[], int h[], int u, int v, int w, int p) {
g[++numE[p]] = (E) { h[u], v, w };
h[u] = numE[p];
}
//多组数据初始化
void inline init() {
ep = false;
memset(dis, 0x3f, sizeof dis);
memset(st, false, sizeof st);
numE[0] = numE[1] = 0;
memset(head, 0, sizeof head);
memset(rhead, 0, sizeof head);
memset(f, -1, sizeof f);
}
// Dijkstra 最短路
priority_queue<PII, vector<PII>, greater<PII> > q;
void inline dijkstra() {
dis[n] = 0; q.push(make_pair(0, n));
while(!q.empty()) {
PII u = q.top(); q.pop();
if(st[u.second]) continue;
st[u.second] = true;
for (int i = rhead[u.second]; i; i = r[i].next) {
int v = r[i].v;
if(dis[u.second] + r[i].w < dis[v]) {
dis[v] = dis[u.second] + r[i].w;
q.push(make_pair(dis[v], v));
}
}
}
} //记忆化搜索
int dfs(int u, int j) {
if(vis[u][j]) { ep = true; return 0; }
if(f[u][j] != -1) return f[u][j]; vis[u][j] = true;
int &val = f[u][j] = 0;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].v, w = e[i].w;
//消耗的冗余长度折算
int k = j - (dis[v] + w - dis[u]);
if(0 <= k && k <= K) (val += dfs(v, k)) %= P;
if(ep) return 0;
} vis[u][j] = false;
if(u == n && j == 0) val = 1;
return val;
} int main() {
int T; scanf("%d", &T);
while(T--) {
init();
scanf("%d%d%d%d", &n, &m, &K, &P);
for (int i = 1, u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(e, head, u, v, w, 0); add(r, rhead, v, u, w, 1);
} dijkstra(); int ans = 0;
for (int i = 0; i <= K; i++) {
memset(vis, false, sizeof vis);
(ans += dfs(1, i)) %= P;
if(ep) break;
}
if(ep) puts("-1");
else printf("%d\n", ans);
}
}

NOIP2017 D1T3 逛公园的更多相关文章

  1. [luogu P3953] [noip2017 d1t3] 逛公园

    [luogu P3953] [noip2017 d1t3] 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N ...

  2. NOIP2017 D1T3逛公园

    DP+最短路 两遍最短路判零环 DP转移f[i][j] 到点i的距离比最短路多j时的方案数 #include<bits/stdc++.h> using namespace std; ; s ...

  3. 【NOIP2017】逛公园 拆点最短路+拓扑(记忆化搜索

    题目描述 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策 ...

  4. 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)

    题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...

  5. NOIP2017:逛公园

    Sol 发现\(NOIP2017\)还没\(AK\)??? 赶紧改 考场上明明打出了\(DP\),没时间了,没判环,重点是没初始化数组,爆\(0\) \(TAT\) 先最短路,然后\(f[i][j]\ ...

  6. 【NOIP2017】逛公园 最短路+DP

    诶,去年场上不会处理$0$的环,只拿了$60$有点可惜. 我们先不管边边权为$0$的边. 我们先跑一次最短路,令$dis[u]$表示从$1$至$u$的最短路的长度. 那么根据题目的要求,从起点走到$u ...

  7. LOJ2316. 「NOIP2017」逛公园【DP】【最短路】【思维】

    LINK 思路 因为我想到的根本不是网上的普遍做法 所以常数出奇的大,而且做法极其暴力 可以形容是带优化的大模拟 进入正题: 首先一个很显然的思路是如果在合法的路径网络里面存在零环是有无数组解的 然后 ...

  8. 【NOIP2017】逛公园 D1 T3

    记忆化搜索 跑一次反向的最短路求出MinDis(u,n)MinDis(u,n)MinDis(u,n) f[u][k]f[u][k]f[u][k]表示dis(u,n)<=MinDis(u,n)+d ...

  9. 【LOJ2316】「NOIP2017」逛公园

    [题目链接] [点击打开链接] [题目概括] 对给定\(K\),起点\(1\)到终点\(n\)中对长度为\([L,L+K]\)的路径计数. \(L\)为\(1\)到\(n\)的最短路长度. [思路要点 ...

随机推荐

  1. 极客mysql02

    mysql 一条更新语句的执行过程: 1.首先客户端通过tcp/ip发送一条sql语句到server层的SQL interface 2.SQL interface接到该请求后,先对该条语句进行解析,验 ...

  2. ip rule 策略路由

    1. 工具安装 yum install iproute 查看工具是否安装 ip -V 2. ip rule 和 ip route ip命令中和策略路由相关的OBJECT有 rule 和 route. ...

  3. TensorFlow_笔记

    Tensorflow 1.基本概念 TensorFlow是一个编程系统,使用图(graphs)来表示计算任务,图(graphs)中的节点称之为op(operation),一个op获得0个或多个Tens ...

  4. 2018.1.15复习_ css+js

    [1]几个常见的css标签:--------------------------------------------------background-color; 设置背景颜色background-p ...

  5. 通过phpmyadmin拿下webshell

    废话: 1.听说网上卖手机的网站很多是诈骗的,搜到一个499元货到付款的手机网站.有点像诈骗,但倒觉得他是在收集用户信息 2.把网站扔到御剑,搜到phpmyadmin的后台,试试下账号密码居然都是默认 ...

  6. Maven一定要会的这几个知识!

    一.Maven概念 Maven是一个项目管理和整合工具.Maven为开发者提供了一套完整的构建生命周期框架.开发团队几乎不用花多少时间就能够自动完成工程的基础构建配置,因为Maven使用了一个标准的目 ...

  7. 安装curl,composer

    wget https://curl.haxx.se/download/curl-7.54.1.tar.gz tar -zvxf curl-7.54.1.tar.gz cd curl-7.54.1 ./ ...

  8. [C#.NET 拾遗补漏]13:动态构建LINQ查询表达式

    最近工作中遇到一个这样的需求:在某个列表查询功能中,可以选择某个数字列(如商品单价.当天销售额.当月销售额等),再选择 小于或等于 和 大于或等于 ,再填写一个待比较的数值,对数据进行查询过滤. 如果 ...

  9. finalize和clean

    弊端 1.执行的时间不确定,资源释放不能靠这2个方法.Cleaner规范指出:"清除方法在System.exit期间的行为是与实现相关的.不确保清除动作是否会被调用." 2#.如果 ...

  10. 【Go语言绘图】gg 库的基本使用

    最近接了个比较大的需求,需要做很多图片处理的事情,比如图片的旋转裁截拼接,各种渐变处理,文字排列,一开始光是想想就头疼.但没有办法,既然已经需求已经到手上了,那就得把它做好才行,于是便开始被迫营业,无 ...