题目传送门

  传送门

题目大意

  给定一个$n$个点$m$条边的带权有向图,问从$1$到$n$的距离不超过最短路长度$K$的路径数。

  跑一遍最短路。

  一个点拆$K + 1$个点,变成一个DAG上路径计数问题。直接拓扑排序加动态规划,如果有一个$n$号点的剩余度数非0,就一个合法的路径上存在零环(这样可以无线走了)。

  于是成功T掉了。

  把拓扑排序变成不建图,从$n$开始记忆化搜索,然后就过了。

  我居然把模数P打错成M调了一个上午,果然我菜啊。。。

  下面这份代码获得了 97 分的好成绩,我也不知道发生了什么。

Code

 /**
* Uoj
* Problem#331
* Accepted
* Time: 2392ms
* Memory: 28196k
*/
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
typedef bool boolean; typedef pair<int, int> pii; const int N = 1e5 + , M = 2e5 + , Kmx = ; const signed int inf = (signed) (~0u >> ); template <typename T>
void pfill(T* pst, const T* ped, T val) {
for ( ; pst != ped; *(pst++) = val);
} typedef class Edge {
public:
int ed, nx, w; Edge(int ed = , int nx = , int w = ):ed(ed), nx(nx), w(w) { }
}Edge; typedef class MapManager {
public:
int *h;
vector<Edge> es; MapManager(int n) {
h = new int[(n + )];
} void init(int n) {
pfill(h + , h + n + , -);
es.clear();
} void addEdge(int u, int v, int w) {
es.push_back(Edge(v, h[u], w));
h[u] = (signed) es.size() - ;
} Edge& operator [] (int p) {
return es[p];
}
}MapManager; typedef class Node {
public:
int p, dis; Node(int p = , int dis = ):p(p), dis(dis) { } boolean operator < (Node b) const {
return dis > b.dis;
}
}Node; int n, m, K, P;
MapManager g(N), _g(N); int add(int a, int b) {
return ((a += b) >= P) ? (a - P) : (a);
} inline void init() {
scanf("%d%d%d%d", &n, &m, &K, &P);
g.init(n + ), _g.init(n + );
for (int i = , u, v, w; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g.addEdge(u, v, w);
_g.addEdge(v, u, w);
}
} int f[N];
priority_queue<Node> que; int& operator * (Node p) {
return f[p.p];
} void dijstra() {
pfill(f + , f + n + , inf);
que.push(Node(, f[] = ));
while (!que.empty()) {
Node e = que.top();
que.pop();
if (*e != e.dis)
continue;
for (int i = g.h[e.p]; ~i; i = g[i].nx)
if (*e + g[i].w < f[g[i].ed])
que.push(Node(g[i].ed, f[g[i].ed] = *e + g[i].w));
}
} int h[N][Kmx];
unsigned char vis[N][Kmx];
boolean cir = false;
int dp(int p, int dif) {
if (dif > K)
return ;
if (dif < )
return ;
assert(dif >= );
if (vis[p][dif] & )
return cir = true;
if (vis[p][dif] & )
return h[p][dif];
vis[p][dif] |= , h[p][dif] = (p == && dif == );
for (int i = _g.h[p], e, nd; ~i; i = _g[i].nx) {
e = _g[i].ed;
if (f[e] == inf)
continue;
nd = f[p] + dif - _g[i].w - f[e];
h[p][dif] = add(h[p][dif], dp(e, nd));
if (cir)
return ;
}
vis[p][dif] ^= ;
return h[p][dif];
} inline void solve() {
dijstra();
if (f[n] == inf) {
puts("");
return;
}
cir = false;
pfill(vis[], vis[n + ], (unsigned char));
int rt = dp(n, );
for (int i = ; i <= K && !cir; i++)
rt = add(rt, dp(n, i));
printf("%d\n", (cir) ? (-) : (rt));
} int T;
int main() {
scanf("%d", &T);
while (T--) {
init();
solve();
}
return ;
}

NOIP 2017 逛公园 - 动态规划 - 最短路的更多相关文章

  1. NOIP 2017 逛公园 记忆化搜索 最短路 好题

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

  2. [NOIp 2017]逛公园

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

  3. 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP

    题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...

  4. NOIP 2017 逛公园 题解

    题面 这道题是一道不错的计数类DP: 首先我们一定要跑一遍dijkstra来求得每个点到1号点的最短路: 注意题干,题中并没有说所有点都可以到达n好点,只说了存在一条1号点到n号点的路径:所以我们在反 ...

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

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

  6. P3953 逛公园(dp,最短路)

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

  7. Luogu3953 NOIP2017逛公园(最短路+拓扑排序+动态规划)

    跑一遍dij根据最短路DAG进行拓扑排序,按拓扑序dp即可.wa了三发感觉非常凉. #include<iostream> #include<cstdio> #include&l ...

  8. 2018.11.01 洛谷P3953 逛公园(最短路+dp)

    传送门 设f[i][j]f[i][j]f[i][j]表示跟最短路差值为iii当前在点jjj的方案数. in[i][j]in[i][j]in[i][j]表示在被选择的集合当中. 大力记忆化搜索就行了. ...

  9. NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)

    神tm比赛时多清个零就有60了T T 首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP.设f[i][j]表示比最短路多走i的长度,到j的方案数. 我们发现如果在最短路上的和零边会有后向性, ...

随机推荐

  1. 第一编,漫漫长征路,第一天学习python

    安装之后,出现 api-ms-win-crt-runtimel1-1-0.dll缺失   还在解决中 重装系统后,安装成功 python的种类: javapython cpython pypy

  2. Redis主从复制详解

    1. 概述 主从复制:主节点负责写数据,从节点负责读数据,主节点定期把数据同步到从节点保证数据的一致性 2. 主从复制的相关操作 (1)配置文件:在从服务器的配置文件中加入 slaveof<ma ...

  3. Tkinter 项目-屏保

    参考教程,以及网上资料,针对小白更好理解 关于tkinter的屏保涉及的知识点和思想 项目分析: 屏保启动方式:手动,自动 敲击键盘或者移动鼠标后,或者其他引发事件,则停止 如果屏保是一幅画的话,则没 ...

  4. Linux基础命令1

    文件的操作: Tab键:自动补齐 反斜杠‘\’:强制换行 Ctrl+u:清空至行首 Ctrl+k:清空至行尾 Ctrl+l:清屏   --clear 清屏 Ctrl+c:取消本次命令编辑,中断当前操作 ...

  5. 解决nohup中不写入日志的问题

    (一)问题描述: nohup 你的程序命令 如: nohup python manage.py runserver 0.0.0.0:6789   (此shell窗口1不要关,另外开一个shell窗口2 ...

  6. 关于 RESTful API 中 HTTP 状态码的定义

    最近正好使用了一会儿 Koa ,在这说一下自己对各个 请求码的见解和使用场景,懒人直接看 200.400.401.403.404.500 就可以了. 其中 2XX/3XX 其实都是请求成功,但是结果不 ...

  7. supervisor无法监听uwsgi

    ➜ ~ sudo supervisorctl data_config FATAL Exited too quickly (process log may have details) data_conf ...

  8. JDK丨WIN10配置JDK1.8 (解决javac不是内部或外部命令,也不是可运行的程序或批处理文件)

    1.下载JDK,安装. 2.配置JDK. (右键我的电脑 - 属性 - 高级系统设置 - 环境变量.) 2.1 添加系统变量JAVA_HOME 变量名:JAVA_HOME 变量值:C:\Program ...

  9. c# 有序链表合并 链表反转

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  10. 大部分教程不会告诉你的 12 个 JS 技巧

    from:https://www.infoq.cn/article/eSYzcMZK4PkOzZC_68fv 在这篇文章中,作者将分享 12 个非常有用的 JavaScript 技巧,可以帮助你写出简 ...