Luogu 3953[NOIP2017] 逛公园 堆优化dijkstra + 记忆化搜索
题解
首先肯定是要求出单源最短路的,我用了堆优化dijikstra ,复杂度 mlogm,值得拥有!(只不过我在定义优先队列时把greater 打成了 less调了好久
然后我们就求出了$i$到源点的最短距离$dis_i$
定义一个数组 $f_{i, k}$表示从源点到节点$i$的距离比$dis_i$大$k$的路径数,另外一个数组$sch_{i,k}$ 记录某条路径上 该状态是否存在, 若在某条路径上出现了第二次, 并且$k <= K$,则可判断有符合条件的$0$环
对于要求的$f_{i, k}$ 需要求出它所有的前驱状态(也就是拓扑), 设它的某一前驱为 $f_{u,t}$则$t = dis_i + k - dis_u - w$ ,$w$为边权。
由于$t + dis_u + w = k + dis_i$, 所以$t - k = dis_i -dis_u - w$, 因为$dis_i$是到 $i$ 的最短距离, 则显然 $dis_i <= dis_u + w$, 得出$t <= k$, 也就是某个点前驱的 $k$值会不断减小,只需要$k >= 0$ 即可进行转移。
有转移方程 : $f_{i, k} = \sum f_{u,t}$ $t >= 0$。 边界为 $f_{1, 0} = 1$。但是若设$f_{1, 0} = 1$为边界状态的话,对于经过 点 $1$ 的0环就无法判断了。
所以我把边界定为$f_{0,0} = 1$,再从 $1 - > 0$连一条 记忆化搜索时需要记录前驱的反向,边权为0, 这样就可以解决$0$环的问题。
最后的答案$ans = \sum\limits_{k=0}^Kf_{n,k}$。
总时间复杂度为$O(MlogM + KN)$
代码
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
#define rd read()
using namespace std;
typedef pair<int,int> P;//用pair来存储dis 与点, 第一个关键字优先排序 const int N = 1e5 + 1e4; int n, m, K, T, head[N], tot, dis[N], f[N][], mod;
vector<int>q[N], w[N];//记录前驱的反向边 bool vis[N], sch[N][], flag = true; priority_queue<P ,vector<P>, greater<P> > pq;//优先队列 struct edge {
int u, v, c, nxt;
}e[N << ]; int read() {
int X = , p = ; char c = getchar();
for(; c > '' || c < ''; c = getchar() ) if( c == '-' ) p = -;
for(; c >= '' && c <= ''; c = getchar() ) X = X * + c - '';
return X * p;
} void add( int u, int v, int c ) {
e[++tot].u = u;
e[tot].v = v;
e[tot].c = c;
e[tot].nxt = head[u];
head[u] = tot;
} void dij() {//求单源最短路
memset( vis, , sizeof(vis));
memset( dis, 0x3f, sizeof(dis));
pq.push(P(, ));
dis[] = ;
for( P u, v; !pq.empty(); ) {
u = pq.top(); pq.pop();
int x = u.second;
if(vis[x]) continue;
vis[x] = ;
for( int i = head[x], nt; i; i = e[i].nxt ) if( dis[nt = e[i].v] > dis[x] + e[i].c && !vis[nt] ) {
dis[nt] = dis[x] + e[i].c;
pq.push(P(dis[nt], nt));
}
}
} int dp( int u, int k ) {//记忆化搜索
if( u == && k == ) return ;
if( f[u][k] != - ) return f[u][k];
f[u][k] = ;
sch[u][k] = ;
for( int i = ; i < (int)q[u].size(); ++i ) {
int nt = q[u][i], t = dis[u] + k - dis[nt] - w[u][i];
if(t < ) continue;
if( sch[nt][t] ) flag = false;//记录路径上的状态
f[u][k] = (f[u][k] + dp(nt, t)) % mod;
}
sch[u][k] = ;//回溯
return f[u][k];
} int main()
{
T = rd;
for(; T; T-- ) {
flag = true;
memset(f, -, sizeof(f));
memset(head, , sizeof(head));
memset(sch, , sizeof(sch));
tot = ;
for( int i = ; i <= n; ++i ) q[i].clear(), w[i].clear();
n = rd; m = rd; K = rd; mod = rd;
for( int i = ; i <= m; ++i ) {
int u = rd, v = rd, c = rd;
add(u, v, c);
q[v].push_back(u);
w[v].push_back(c);
}
q[].push_back();
w[].push_back();
dij();
dis[] = ;
int ans = ;
for( int i = ; i <= K; ++i ) ans = (ans + dp(n, i)) % mod;
if(!flag) printf("-1\n");
else printf("%d\n", ans);
}
}
Luogu 3953[NOIP2017] 逛公园 堆优化dijkstra + 记忆化搜索的更多相关文章
- [NOIP2017] 逛公园 (最短路,动态规划&记忆化搜索)
题目链接 Solution 我只会60分暴力... 正解是 DP. 状态定义: \(f[i][j]\) 代表 \(1\) 到 \(i\) 比最短路长 \(j\) 的方案数. 那么很显然最后答案也就是 ...
- HDU1142 (Dijkstra+记忆化搜索)
A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Jav ...
- luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)
先跑一边dijkstra算出从1到i的最短距离dis[i] 然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数 答案就是$\sum\limits_{i=0}^{k} ...
- 洛谷3953 (NOIp2017) 逛公园——记忆化搜索+用栈判0环
题目:https://www.luogu.org/problemnew/show/P3953 因为K只有50,所以想到用dp[ cr ][ j ]表示在点cr.比最短路多走了 j 的方案数.(看了TJ ...
- HDU 1142 A Walk Through the Forest(Dijkstra+记忆化搜索)
题意:看样子很多人都把这题目看错了,以为是求最短路的条数.真正的意思是:假设 A和B 是相连的,当前在 A 处, 如果 A 到终点的最短距离大于 B 到终点的最短距离,则可以从 A 通往 B 处,问满 ...
- Luogu P2149 [SDOI2009]Elaxia的路线(最短路+记忆化搜索)
P2149 [SDOI2009]Elaxia的路线 题意 题目描述 最近,\(Elaxia\)和\(w**\)的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的 ...
- Luogu P3953 [NOIP2017]逛公园
题目 首先我们跑出从\(1\)出发的最短路\(d1\)和反图上从\(n\)出发的最短路\(dn\). 然后我们处理出长度不超过\(d1_n+k\)的最短路边集,给它拓扑排序. 如果存在环,那么这个环一 ...
- 堆优化dijkstra
单源最短路径 题目链接:https://www.luogu.org/problemnew/show/P4779 直到做了这个题才发现我之前写的堆优化dijkstra一直是错的.. 这个堆优化其实很容易 ...
- Luogu P3953 逛公园(最短路+记忆化搜索)
P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...
随机推荐
- 基于Linux的Samba开源共享解决方案测试(五)
对于客户端的网络监控如图: 双NAS网关50Mb码率视音频文件的稳定写测试结果如下: 100Mb/s负载性能记录 NAS网关资源占用 稳定写 稳定写 CPU空闲 内存空闲 网卡占用 NAS1 16个稳 ...
- ioi2016aliens
/* 首先考虑点在直线的两边效果一样 于是转移到一边 之后发现当我们覆盖某些点时,有其他的一些点一定会被覆盖 我们找出所有必须覆盖的点 之后我们发现我们找到的这些点 将其按照x递增排序 那么y也是递增 ...
- 学大伟业Day1解题报告
学大伟业Day1解题报告 张炳琪 一. 时间分配 T1:30分钟 T2: 60分钟 T3:100分钟 二.答题情况及错因 T1:100 T2:55 T3 ...
- webpack(5)--Resolve
Resolve webpack在启动后会从配置的入口模块触发找出所有依赖的模块,Resolve配置webpack如何寻找模块对应的文件.webpack内置JavaScript模块化语法解析功能,默认会 ...
- 简单工厂法( Factory Method)
工厂方法 (Factory Method) Define an interface for creating an object ,but let subclasses decide which cl ...
- (16/24) webpack打包后的调试方法
在程序开发中,调试程序是最频繁的,那使用了webpack后,所有的代码都打包到了一起,这给调试带来了困难,但是webpack在设计时就已经考虑好了这点,它支持生产Source Maps来方便我们的调试 ...
- spring-CXF-maven
pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w ...
- HTML5 Canvas ( 贝塞尔曲线, 一片星空加绿地 ) quadraticCurveTo, bezierCurveTo
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- leetcode191
public class Solution { public int HammingWeight(uint n) { var list = new List<uint>(); do { ; ...
- 深入浅出理解依赖注入这种由外部负责其依赖需求的行为,我们可以称其为 “控制反转(IoC)”
原文地址: http://www.insp.top/learn-laravel-container ,转载务必保留来源,谢谢了! 这个组件现在可以很简单的获取到它所需要的服务,服务采用延迟加载的方式, ...