NOIP 2017 逛公园 - 动态规划 - 最短路
跑一遍最短路。
一个点拆$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 逛公园 - 动态规划 - 最短路的更多相关文章
- NOIP 2017 逛公园 记忆化搜索 最短路 好题
题目描述: 策策同学特别喜欢逛公园.公园可以看成一张N个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. ...
- [NOIp 2017]逛公园
Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
- 洛谷 P3953 [ NOIP 2017 ] 逛公园 —— 最短路DP
题目:https://www.luogu.org/problemnew/show/P3953 主要是看题解...还是觉得好难想啊... dfs DP,剩余容量的损耗是边权减去两点最短路差值...表示对 ...
- NOIP 2017 逛公园 题解
题面 这道题是一道不错的计数类DP: 首先我们一定要跑一遍dijkstra来求得每个点到1号点的最短路: 注意题干,题中并没有说所有点都可以到达n好点,只说了存在一条1号点到n号点的路径:所以我们在反 ...
- 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)
题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...
- P3953 逛公园(dp,最短路)
P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
- Luogu3953 NOIP2017逛公园(最短路+拓扑排序+动态规划)
跑一遍dij根据最短路DAG进行拓扑排序,按拓扑序dp即可.wa了三发感觉非常凉. #include<iostream> #include<cstdio> #include&l ...
- 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]表示在被选择的集合当中. 大力记忆化搜索就行了. ...
- NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)
神tm比赛时多清个零就有60了T T 首先跑出1起点和n起点的最短路,因为k只有50,所以可以DP.设f[i][j]表示比最短路多走i的长度,到j的方案数. 我们发现如果在最短路上的和零边会有后向性, ...
随机推荐
- QQ机器人
先说下整体思路1.首先要借助一个QQ 插件,用来接收消息 发送消息2.要用个QQ 小号,这个QQ 你不能用来登,因为他相当于那个机器人3.要借助大神开发的SDK ,就是别人写的底层交互 ,我们只需要关 ...
- 第二次C语言实验
Part1: printf(),scanf()函数的用法 /* C语言程序设计教程学习指导>p119 实验内容(2) 这是一个格式化输入输出函数及格式符使用练习 找出两处错误,修改并运行程序 为 ...
- 洛谷P4640 王之财宝 [BJWC2008] 数论
正解:容斥+Lucas+组合数学 解题报告: 传送门! 和上一篇题解的题差不多,,,双倍经验趴大概算 还是说下还是有点儿区别的来着$QwQ$ 两个小差别分别港下$QwQ$ 首先有$m-n$件是无穷个的 ...
- shell 字符串比较 算数比较 文件条件测试
set-group-id即set-gid -->授予了程序其所在组的访问权限 set-user-id即set-uid -->授予了程序其拥有者的访问权限而不是其使用者的访问权限 set-g ...
- keras训练cnn模型时loss为nan
keras训练cnn模型时loss为nan 1.首先记下来如何解决这个问题的:由于我代码中 model.compile(loss='categorical_crossentropy', optimiz ...
- 树状数组-逆序对-HDU6318
Swaps and Inversions Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- 简单了解request与response
本文对 request. response 简单描述,未涉及到具体的浏览器缓存.重定向.请求转发等代码部分. 一.Web服务器,浏览器,代理服务器 在看 response.request 对象之前,先 ...
- 如何查看正在执行sql的语句及其父语句调用?如何查看正在执行SQL的具体参数值与执行计划?
---SQL Server查询正在执行的SQL语句及执行计划 select ds.session_id,dr.start_time,db_name(dr.database_id),dr.blockin ...
- 使用charles模拟慢速网络
1.设置慢速网络 点击导航栏的proxy---throttle setting来设置想要的网络情况, 其中有两种方法: (1)勾选Enable Throttling,在Throttle presett ...
- Java开发规范总结
Service / DAO 层方法命名规约: 1 ) 获取单个对象的方法用 get 做前缀.2 ) 获取多个对象的方法用 list 做前缀.3 ) 获取统计值的方法用 count 做前缀.4 ) 插 ...