DP+图论大毒瘤。

推荐这个博客

先跑两遍最短路,搞掉一些无用点。

然后选出最短路上的边,做拓扑排序。

然后每层DP。

具体看代码。

用到的数组较多,记得清空。

 #include <cstdio>
#include <queue>
#include <cstring>
const int N = ; inline void read(int &x) {
x = ;
char c = getchar();
while(c > '' || c < '') {
c = getchar();
}
while(c <= '' && c >= '') {
x = (x << ) + (x << ) + c - ;
c = getchar();
}
return;
} struct Edge {
int nex, len, v;
}edge[N << ], edge_[N << ]; int top; int n, m, K, MO, f[N][];
int e[N], e_[N], d[N], d_[N];
bool vis[N], use_e[N << ], use_p[N];
int topo[N], in[N], TOPO; inline void add(int x, int y, int z) {
edge[++top].v = y;
edge[top].len = z;
edge[top].nex = e[x];
e[x] = top;
edge_[top].v = x;
edge_[top].len = z;
edge_[top].nex = e_[y];
e_[y] = top;
return;
} inline void SPFA() {
std::queue<int> Q;
memset(vis, , sizeof(vis));
memset(d, 0x3f, sizeof(d));
Q.push();
d[] = ;
vis[] = ;
while(!Q.empty()) {
int x = Q.front();
Q.pop();
vis[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(d[y] > d[x] + edge[i].len) {
d[y] = d[x] + edge[i].len;
if(!vis[y]) {
vis[y] = ;
Q.push(y);
}
}
}
}
for(int i = ; i <= n; i++) {
if(d[i] == 0x3f3f3f3f) {
use_p[i] = ;
}
}
return;
} inline void SPFA_() {
std::queue<int> Q;
memset(vis, , sizeof(vis));
memset(d_, 0x3f, sizeof(d_));
Q.push(n);
vis[n] = ;
d_[n] = ;
while(!Q.empty()) {
int x = Q.front();
Q.pop();
vis[x] = ;
for(int i = e_[x]; i; i = edge_[i].nex) {
int y = edge_[i].v;
if(d_[y] > d_[x] + edge_[i].len) {
d_[y] = d_[x] + edge_[i].len;
if(!vis[y]) {
vis[y] = ;
Q.push(y);
}
}
}
}
for(int i = ; i <= n; i++) {
if(d_[i] == 0x3f3f3f3f) {
use_p[i] = ;
}
}
return;
} inline void solve() {
int x, y, z;
read(n);
read(m);
read(K);
read(MO);
top = ;
memset(e, , sizeof(e));
memset(e_, , sizeof(e_));
for(int i = ; i <= m; i++) {
read(x);
read(y);
read(z);
add(x, y, z);
}
memset(use_p, , sizeof(use_p));
//printf("use_p %d \n", use_p[2]);
SPFA_();
SPFA(); memset(use_e, , sizeof(use_e));
memset(in, , sizeof(in));
for(int i = ; i <= m; i++) {
int x = edge_[i].v;
int y = edge[i].v;
if(use_p[x] && use_p[y] && d[x] + edge[i].len == d[y]) {
use_e[i] = ;
in[y]++;
}
} /// topo sort
TOPO = ;
std::queue<int> Q;
for(int i = ; i <= n; i++) {
if(!in[i]) {
Q.push(i);
}
}
while(!Q.empty()) {
int x = Q.front();
Q.pop();
topo[++TOPO] = x;
for(int i = e[x]; i; i = edge[i].nex) {
if(!use_e[i]) {
continue;
}
int y = edge[i].v;
in[y]--;
if(!in[y]) {
Q.push(y);
}
}
}
if(TOPO < n) {
printf("-1\n");
return;
} /// DP
memset(f, , sizeof(f));
f[][] = ;
for(int k = ; k <= K; k++) {
for(int a = ; a <= n; a++) {
int x = topo[a];
if(!use_p[x]) {
continue;
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(!use_p[y]) {
continue;
}
int temp = d[x] + edge[i].len - d[y] + k;
if(temp > K) {
//printf("temp = %d > K \n", temp);
continue;
}
//printf("f[%d][%d] += f[%d][%d] ", y, temp, x, k);
f[y][temp] += f[x][k];
f[y][temp] %= MO;
//printf("= %d \n", f[y][temp]);
}
}
} int ans = ;
for(int i = ; i <= K; i++) {
ans = (ans + f[n][i]) % MO;
}
printf("%d\n", ans); return;
} int main() {
int T;
read(T);
while(T--) {
solve();
}
return ;
}

AC代码

感觉是我用memset最多的一次了。

有个记忆化搜索的写法,先坑着。

洛谷P3953 逛公园的更多相关文章

  1. 洛谷P3953 逛公园(NOIP2017)(最短/长路,拓扑排序,动态规划)

    洛谷题目传送门 又是一年联赛季.NOIP2017至此收官了. 这个其实是比较套路的图论DP了,但是细节有点恶心. 先求出\(1\)到所有点的最短路\(d1\),和所有点到\(n\)的最短路\(dn\) ...

  2. 洛谷P3953逛公园

    题目 作为\(NOIp2017D1T3\) 这个题还是很良心的,至少相对于\(NOIp2018\)来说,希望\(NOIp2019\)不会这么坑吧. 这个题可以作为记忆化搜索的进阶题了,做这个题的方法也 ...

  3. 洛谷 P3953 逛公园

    题目链接 思路 首先没有0边,且k为0的情况就是最短路计数. 如果k不为0,看到k<=50,想到dp. 设f[u][i]表示到达u点比最短路多走i的路径数,转移到v点. f[u][i]+=f[v ...

  4. 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]表示在被选择的集合当中. 大力记忆化搜索就行了. ...

  5. 洛谷P3953 逛公园 [noip2017] 图论+dp

    正解:图论(最短路)+dp(记忆化搜索) 解题报告: 这题真的是个好东西! 做了这题我才发现我的dij一直是错的...但是我以前用dij做的题居然都A了?什么玄学事件啊...我哭了TT 不过其实感觉还 ...

  6. 洛谷P3953 逛公园(dp 拓扑排序)

    题意 题目链接 Sol 去年考NOIP的时候我好像连最短路计数都不会啊qwq.. 首先不难想到一个思路,\(f[i][j]\)表示到第\(i\)个节点,与最短路之差长度为\(j\)的路径的方案数 首先 ...

  7. 洛谷 P3953 逛公园【spfa+记忆化dfs+bfs】

    spfa预处理出最短路数组dis,然后反向建边bfs出ok[u]表示u能到n点 然后发现有0环的话时候有inf解的,先dfs找0环判断即可 然后dfs,设状态f[u][v]为到u点,还可以跑最短路+v ...

  8. 洛谷 P1053 逛公园 解题报告

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

  9. UVA 1400."Ray, Pass me the dishes!" -分治+线段树区间合并(常规操作+维护端点)并输出最优的区间的左右端点-(洛谷 小白逛公园 升级版)

    "Ray, Pass me the dishes!" UVA - 1400 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...

随机推荐

  1. 2018年高教社杯全国大学生数学建模竞赛B题解题思路

    题目 先贴下B题的题目吧 问题B    智能RGV的动态调度策略 图1是一个智能加工系统的示意图,由8台计算机数控机床(Computer Number Controller,CNC).1辆轨道式自动引 ...

  2. 001_IntelliJ IDEA详细安装步骤

    安装IntelliJ IDEA 一.安装JDK 1 下载最新的jdk,这里下的是jdk-8u66 2 将jdk安装到默认的路径C:\Program Files\Java目录下 二.安装IntelliJ ...

  3. Redis Cluster日常操作命令梳理

    在之前的一篇文章已经介绍了Redis Cluster及其部署,下面说下Redis Cluster日常操作命令: 一.以下命令是Redis Cluster集群所独有的,执行下面命令需要先登录redis: ...

  4. Python练习之用户登录-5

    格式化输出 %s %d %% 编码: ascii 只能显示英文,特殊字符,数字. 万国码:unicode 最开始16位,中文不够32位 4个字节. 占用资源多. 升级:utf-8 utf-16 utf ...

  5. Visual Studio 2013编辑器+SourceTree代码管理工具及扩展工具

    Visual Studio 2013: 美国微软公司的编辑开发工具 扩展工具: Resharper:进行深度代码分析,函数深度查询(ctrl+鼠标左): Grunt:是基于Node.js的项目以自动化 ...

  6. C# wkhtmltopdf 将html转pdf(详解)

    https://www.cnblogs.com/louby/p/905198.html转自,看文章只放了代码看起来云里雾里的,在此做些解析 使用说明: 1.首先呢,得安装下软件,地址下面有链接,文件里 ...

  7. springboot整合druid连接池、mybatis实现多数据源动态切换

    demo环境: JDK 1.8 ,Spring boot 1.5.14 一 整合durid 1.添加druid连接池maven依赖 <dependency> <groupId> ...

  8. shell脚本第一课

    shell脚本的文件名一般是以.sh结尾,也可以以其他格式如.txt,甚至不加后缀. 脚本的第一行的#!/bin/bash表示指定脚本执行时的解析器. #!/bin/bash #文件名:test.sh ...

  9. window.setTimeout

    https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout

  10. activiti engine.schema.update DB_SCHEMA_UPDATE_FALSE

    engine.properties # engine propertiesengine.schema.update=trueengine.activate.jobexecutor=falseengin ...