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. 电梯调度系统(界面由C图形库编绘)

    1.编程题目 电梯调度系统 2.结对编程组员 黄冠译,刘畅 3.编程语言 C语言图形库 4题目要求 编写人员:刘畅,黄冠译 代码如下: # include <stdio.h> # incl ...

  2. Code Review —— by12061154Joy

    对结对队友刘丽萍的代码进行了复审: 优点: 1,代码逻辑正确,基本能够完全需求 2,用了不少C#自带的函数,第一次写C#,相信是查阅了不少资料,虽然还有很多地方值得优化,不过第一次能做到这样已经很不错 ...

  3. Week 2 代码规范

    Question 1: 这些规范都是官僚制度下产生的浪费大家的编程时间.影响人们开发效率, 浪费时间的东西. My opinion: 我认为恰恰相反,这个可以提高人们的开发效率. 在团队合作当中,如果 ...

  4. Struts2中的图片验证码

    1.Struts中建一个action <action name="Code" class="LoginAction" method="code& ...

  5. 【目标跟踪】相关滤波算法之MOSSE

    简要 2010年David S. Bolme等人在CVPR上发表了<Visual Object Tracking using Adaptive Correlation Filters>一文 ...

  6. Maven -Maven配置tomcat插件 两种

    Maven Tomcat插件现在主要有两个版本,tomcat-maven-plugin和tomcat7-maven-plugin,使用方式基本相同. tomcat-maven-plugin 插件官网: ...

  7. [转帖]Nginx的超时keeplive_timeout配置详解

    Nginx的超时keeplive_timeout配置详解 https://blog.csdn.net/weixin_42350212/article/details/81123932   Nginx  ...

  8. 通过Oracle DUMP 文件获取表的创建语句

    1. 有了dump文件之后 想获取表的创建语句. 之前一直不知道 dump文件能够直接解析文件. 今天学习了下 需要的材料. dump文件, dump文件对应的schema和用户. 以及一个版本合适的 ...

  9. webpack4.x相关笔记整理

    概念 Webpack是一个模块打包机,它可以将我们项目中的所有js.图片.css等资源,根据其入口文件的依赖关系,打包成一个能被浏览器识别的js文件.能够帮助前端开发将打包的过程更智能化和自动化. W ...

  10. mysql理论结合实际篇(一)

    最近两天做需求,是要将退款和退货报表里使用的临时表改用固定表, 自己建表时,如(只是举例): CREATE TABLE tasks ( task_id INT UNSIGNED NOT NULL AU ...