题解

首先肯定是要求出单源最短路的,我用了堆优化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 + 记忆化搜索的更多相关文章

  1. [NOIP2017] 逛公园 (最短路,动态规划&记忆化搜索)

    题目链接 Solution 我只会60分暴力... 正解是 DP. 状态定义: \(f[i][j]\) 代表 \(1\) 到 \(i\) 比最短路长 \(j\) 的方案数. 那么很显然最后答案也就是 ...

  2. HDU1142 (Dijkstra+记忆化搜索)

    A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  3. luogu3953 [NOIp2017]逛公园 (tarjan+dijkstra+记忆化搜索)

    先跑一边dijkstra算出从1到i的最短距离dis[i] 然后建反向边 从n开始记忆化搜索,(p,k)表示1到p的距离=dis[p]+k的方案数 答案就是$\sum\limits_{i=0}^{k} ...

  4. 洛谷3953 (NOIp2017) 逛公园——记忆化搜索+用栈判0环

    题目:https://www.luogu.org/problemnew/show/P3953 因为K只有50,所以想到用dp[ cr ][ j ]表示在点cr.比最短路多走了 j 的方案数.(看了TJ ...

  5. HDU 1142 A Walk Through the Forest(Dijkstra+记忆化搜索)

    题意:看样子很多人都把这题目看错了,以为是求最短路的条数.真正的意思是:假设 A和B 是相连的,当前在 A 处, 如果 A 到终点的最短距离大于 B 到终点的最短距离,则可以从 A 通往 B 处,问满 ...

  6. Luogu P2149 [SDOI2009]Elaxia的路线(最短路+记忆化搜索)

    P2149 [SDOI2009]Elaxia的路线 题意 题目描述 最近,\(Elaxia\)和\(w**\)的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的 ...

  7. Luogu P3953 [NOIP2017]逛公园

    题目 首先我们跑出从\(1\)出发的最短路\(d1\)和反图上从\(n\)出发的最短路\(dn\). 然后我们处理出长度不超过\(d1_n+k\)的最短路边集,给它拓扑排序. 如果存在环,那么这个环一 ...

  8. 堆优化dijkstra

    单源最短路径 题目链接:https://www.luogu.org/problemnew/show/P4779 直到做了这个题才发现我之前写的堆优化dijkstra一直是错的.. 这个堆优化其实很容易 ...

  9. Luogu P3953 逛公园(最短路+记忆化搜索)

    P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...

随机推荐

  1. GSO/TSO/GRO等对VirtIO虚机的网络性能影响分析(by quqi99)

    作者:张华  发表于:2016-04-05版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 ( http://blog.csdn.net/quqi99 ) IP层 ...

  2. 包与常用模块:time,sys。

    一  包的初识: 首先包在pycharm中的表现形式为packa文件夹:在python3种那么我们创建一个packa时会发现下边会自动跟一个—init—.py文件 包的定义:包就是一个包含有——ini ...

  3. Python Flask 多环境配置

    Python里取配置文件的时候,之前是使用的ini文件和python里configparser 模块: 可参考:https://www.cnblogs.com/feeland/p/4514771.ht ...

  4. Django高级admin续

    ModelAdmin对象 ModelAdmin类是模型在Admin界面中的表示形式 定义:定义一个类,继承于admin.ModelAdmin,注册模型时使用这个类 class HeroAdmin(ad ...

  5. Code First use dotConnect for MySQL

    http://www.dotblogs.com.tw/yc421206/archive/2014/03/24/144507.aspx dotConnect for MySQL 是一家強大的 3rd C ...

  6. [python爬虫] 爬取图片无法打开或已损坏的简单探讨

    本文主要针对python使用urlretrieve或urlopen下载百度.搜狗.googto(谷歌镜像)等图片时,出现"无法打开图片或已损坏"的问题,作者对它进行简单的探讨.同时 ...

  7. Excel函数使用

    Excel函数使用: count&countif today&now count count() 仅可以统计数字类型的单元格个数 countif 根据条件来选择统计 countif(D ...

  8. mysql大表优化

    https://segmentfault.com/a/1190000006158186 https://tech.meituan.com/mysql-index.html http://www.cnb ...

  9. win10关闭后台应用程序进程的方法

    一)win10系统后台应用有两大特点: 1.win10系统有许多系统自带应用软件,在系统任务栏中看不到任何自带的应用程序运行 2.但通过任务管理器的进程中,可直观的看到许多非系统进程正在运行. 二)后 ...

  10. java的反射应用

    class B{ public static void main(String[] arg){ Class c_a = Class.forName(packageName + "." ...