题目传送门

  传送门

题目大意

  给定一个$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. Django集成Bootstrap美化后台

    1.pip install bootstrap-admin 2.编辑项目下的settings.py,增加下面行,放在最前面 3.编辑项目下的settings.py,增加下面行

  2. subline text3 安装 rem装换工具

    CSSREM 一个CSS的px值转rem值的Sublime Text 3自动完成插件. 插件效果如下: 安装 下载本项目,比如:git clone https://github.com/flashli ...

  3. ZPW-2000电气绝缘移频轨道电路

    1.该轨道电路是个什么样子?(图片) 整个轨道电路不仅都在室外,其中还包括室内设备.其中室内设备包括发送器.接收器和衰耗盒.室内设备和室外设备通过一根电缆相连. 机柜 2.移频轨道电路有什么作用? z ...

  4. Linux替换动态库导致正在运行的程序崩溃

    在替换so文件时,如果在不停程序的情况下,直接用 cp new.so old.so 的方式替换程序使用的动态库文件会导致正在运行中的程序崩溃.解决的办法是采用“rm+cp” 或“mv+cp” 来替代直 ...

  5. awk 实战

    awk 一些好玩的用法.有什么不错的点子可以留言,发挥出awk牛逼功能 分离mac地址 ifconfig wlan0 | grep eth | awk '{n=split($2,arr,": ...

  6. L1-039. 古风排版

    L1-039. 古风排版 中国的古人写文字,是从右向左竖向排版的.本题就请你编写程序,把一段文字按古风排版. 输入格式: 输入在第一行给出一个正整数N(<100),是每一列的字符数.第二行给出一 ...

  7. 学习记录----简单的原生js路由

    在以前的web程序中,路由字眼只出现在后台中.但是随着SPA单页面程序的发展,便出现了前端路由一说.单页面顾名思义就是一个网站只有一个html页面,但是点击不同的导航显示不同的内容,对应的url也会发 ...

  8. C++ MFC万能的类向导

    MFC的类向导 只要你掌握了类向导,你基本就已经掌握了MFC了,毕竟布局和代码都是自动生成,再加上C++基础上手还是挺快的,剩下的就是多多练习了. 转自: https://blog.csdn.net/ ...

  9. NodeMan介绍

    近年来,随着nodejs的突飞猛进,node项目数量增长迅猛,node项目完美的阐释了“开箱即用”的理念.小到创业公司,大到阿里这样的巨头,背后均有node的身影. node项目基于Chrome的V8 ...

  10. 66.ajax--ajax请求多个url解决办法

    ajax请求多个url解决办法 以下四种方法是我找的,我也进行实践过. 测试中有四个请求接口,原本需要13S,用了第三种方法缩减到7S,但是仍不能达到2S以内. 所以仅供参考,待我找到能缩减到2S以内 ...