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的方案数. 我们发现如果在最短路上的和零边会有后向性, ...
随机推荐
- 2.2String工具类
1:split方法 public class SplitDemo1 { public static String[] name = new String[20]; public SplitDemo1( ...
- MFC全屏显示和多窗口动态显示的一些技巧和方法
一.全屏 1.全屏窗口从dialogex继承,因为要处理一些东西 2.全屏代码,这样设置后尺寸不会出bug,只设置为最大值的话容易出bug //get current system resolutio ...
- Vue2.2版本学习小结
一.项目初始化继续参考这里 https://github.com/vuejs-templates/webpack-simple 或者 https://github.com/vuejs-template ...
- 《PHP内核剖析 - 变量/内存管理》
本文总结自: <PHP7 内核剖析 - 变量的内部实现> 一:变量的实现 - 变量是一个语言实现的基础. - 在PHP中,变量的组成部分为 变量名(zval) 变量值(zend_value ...
- NodeJS笔记(五) 使用React Native 创建第一个 Android APP
参考:原文地址 几个月前官方推出了快速创建工具包,由于对React Native不熟悉这里直接使用这2个工具包进行创建 1. create-react-native-app(下文简称CRNA): 2. ...
- 周末没事干就看CSS JS Python ThinkPHP的书,照着例子运行就行,可以增强信心(www.delphihtmlcomponents.com 是神器,也可以帮助我学习。还有虚拟机运行Web)
https://www.javatpoint.com/javascript-tutorialhttps://www.javatpoint.com/html-tutorialhttps://www.ja ...
- Elasticsearch学习笔记(九)partial update
一.什么是partial update? PUT /index/type/id,创建文档&替换文档,就是一样的语法 一般对应到应用程序中,每次的执行流程基本是这样的: (1)应用程序先发起一个 ...
- VisualStudioCode创建的asp.net core控制台程序部署到linux
1.asp.net core控制台程序 static void Main(string[] args) { ; ) { Console.WriteLine("Hello World!&quo ...
- django集成ansibe实现自动化
动态生成主机列表和相关参数 def create_admin_domain(admin_node): workpath = BASE_DIR + '/tools/ansible/script' hos ...
- 使用LVM进行分区扩展的记录
场景:在磁盘分区空间不够的情况下,要扩展分区空间 因为使用的是虚拟机,所以可以对原有的硬盘上进行扩展,而不需要新增一个硬盘 1.扩展磁盘并使用fdisk工具进行分区 虚拟机关机后对磁盘进行扩展,扩展到 ...