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\) 号点是公 ...
随机推荐
- IPv4报文分片
1:为什么需要分片 每个数据链路层协议都有自己的帧格式,在这个格式中有一个字段是"数据字段最大长度"(MTU,最大传输单元),当数据报被封装成帧时,数据报的总长度必须小于这个最大长 ...
- OpenACC 云水参数化方案
▶ 书上第十三章,用一系列步骤优化一个云水参数化方案.用于熟悉 Fortran 以及 OpenACC 在旗下的表现 ● 代码,文件较多,放在一起了 ! main.f90 PROGRAM main US ...
- C# EF 基础操作
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- java 调用apache.commons.codec的包简单实现MD5加密
转自:https://blog.csdn.net/mmd1234520/article/details/70210002/ import java.security.MessageDigest; im ...
- Spring MVC 重定向
@RequestMapping("/testRedirect") public String testRedirect(){ System.out.println("te ...
- Spring MVC 视图及视图解析器
org.springframework.web.servlet.view.InternalResoureceViewResolve 把逻辑视图改为物理视图 可混用多种视图 不进过Handler直接进入 ...
- as3 文档类判断是否被加载
if (!stage) { trace(("被加载->this.parent:" + this.parent)); }else { trace(("单独打开-> ...
- python: no module named bz2
https://stackoverflow.com/questions/8115280/importerror-no-module-named-bz2-for-python-2-7-2 centos6 ...
- Mysql 知识(3)
1.如何登陆mysql数据库 mysql -u username -p 2.如何开启/关闭mysql服务 service mysql start/stop 3.查看mysql的状态 service m ...
- denyhosts配置详解
DenyHosts官方网站为:http://denyhosts.sourceforge.net 用DenyHosts可以阻止试图猜测SSH登录口令,它会分析/var/log/secure等日志文件,当 ...