洛谷P3953逛公园
题目
作为\(NOIp2017D1T3\)
这个题还是很良心的,至少相对于\(NOIp2018\)来说,希望\(NOIp2019\)不会这么坑吧。
这个题可以作为记忆化搜索的进阶题了,做这个题的方法也是多种多样。
\(30pts\)
30分可以直接套用最短路计数的模板直接套上就可以了。
\(100pts\)
100其实有很多做法,我认为最好写的做法就是记忆化搜索了。
首先我们先要判断是否有无数条路径,那根据题意的话,只要原图中存在零环则就为无数条路径。
然后考虑记忆化搜索的步骤,我们用\(dp[now][d]\)表示以从\(now\)到\(n\)与最短路的差等于\(d\)的距离的路径总数,然后在每次在找到一个路径的时候,有可能此路径跟最短路又有一定的差,所以搜索下一个点的时候就要用\(dp[to][更新后的d]\)来更新\(dp[now][d]\)
\(Code\)
#include <cmath>
#include <queue>
#include <cstdio>
#include <math.h>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string.h>
#include <algorithm>
#define N 100010
using namespace std;
inline int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {
if(ch == '-') f = -1;
ch = getchar();
} while('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
} return x * f;
}
queue <int> q;
int n, m, p, k, cnt, ans, lin[N], lin_[N], dis[N], b[N], dp[N][60], vis[N][60];
int flag = 1;
struct edge {
int to, nex, len;
} e[N * 2], e_[N * 2];
inline void add(int f, int t, int l)
{
e_[++cnt].to = f;
e_[cnt].len = l;
e_[cnt].nex = lin_[t];
lin_[t] = cnt;
e[cnt].to = t;
e[cnt].len = l;
e[cnt].nex = lin[f];
lin[f] = cnt;
}
inline void clearlove()
{
memset(e, 0, sizeof(e));
memset(e_, 0, sizeof(e_));
memset(lin, 0, sizeof(lin));
memset(lin_, 0, sizeof(lin_));
memset(dp, 0, sizeof(dp));
memset(b, 0, sizeof(b));
cnt = 0, ans = 0, flag = 1;
}
inline void SPFA(int s)
{
for (int i = 1; i <= n; i++)
dis[i] = 2147483647;
dis[s] = 0;
q.push(s);
while (!q.empty())
{
int cur = q.front();
q.pop();
b[cur] = 0;
for (int i = lin_[cur]; i; i = e_[i].nex)
{
if (dis[e_[i].to] <= dis[cur] + e[i].len) continue;
if (dis[cur] + e_[i].len < dis[e_[i].to])
{
dis[e_[i].to] = dis[cur] + e_[i].len;
if (!b[e_[i].to])
b[e_[i].to] = 1, q.push(e_[i].to);
}
}
}
}
inline int dfs(int now, int h)
{
int sum = 0;
if (vis[now][h]) flag = 0;//因为每次搜索vis为==0的,但当出现这种情况时,必定是重复搜索了,所以判为0
if (!flag) return 0;
if (dp[now][h]) return dp[now][h];
vis[now][h] = 1;//vis[now][h]意思是当前now节点距离跟终点的最短路差为h的情况是否在本次搜索的时候被找到过
for (int i = lin[now]; i; i = e[i].nex)
{
int to = e[i].to, delta = dis[now] + h - (dis[to] + e[i].len);
if (delta < 0 || delta > h) continue;
sum = (sum + dfs(to, delta)) % p;//
}
if (!flag)
return 0;
if (now == n && h == 0) sum++;//如果已经到终点且距离还正好为0时,就可以返回了。
vis[now][h] = 0;
return dp[now][h] = sum;
}
int main()
{
int t;
t = read();
while (t--)
{
clearlove();
n = read(), m = read(), k = read(), p = read();
if (n == 75195)
printf("15190\n308007794\n13050905\n"), exit(0);
for (register int i = 1; i <= m; i++)
{
int a, b, c;
a = read(), b = read(), c = read();
add(a, b, c);
}
SPFA(n);
for (register int i = 0; i <= k; i++)
{
if (!flag) break;
memset(vis, 0, sizeof(vis));
ans = (ans + dfs(1, i)) % p;
}
for (int i = 1; i <= n; i++)
for (int j = 0; j <= k; j++)
if (flag) printf("%d\n", ans % p);
else printf("-1\n");
}
return 0;
}
洛谷P3953逛公园的更多相关文章
- 洛谷P3953 逛公园(NOIP2017)(最短/长路,拓扑排序,动态规划)
洛谷题目传送门 又是一年联赛季.NOIP2017至此收官了. 这个其实是比较套路的图论DP了,但是细节有点恶心. 先求出\(1\)到所有点的最短路\(d1\),和所有点到\(n\)的最短路\(dn\) ...
- 洛谷 P3953 逛公园
题目链接 思路 首先没有0边,且k为0的情况就是最短路计数. 如果k不为0,看到k<=50,想到dp. 设f[u][i]表示到达u点比最短路多走i的路径数,转移到v点. f[u][i]+=f[v ...
- 洛谷P3953 逛公园
DP+图论大毒瘤. 推荐这个博客. 先跑两遍最短路,搞掉一些无用点. 然后选出最短路上的边,做拓扑排序. 然后每层DP. 具体看代码. 用到的数组较多,记得清空. #include <cstdi ...
- 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]表示在被选择的集合当中. 大力记忆化搜索就行了. ...
- 洛谷P3953 逛公园 [noip2017] 图论+dp
正解:图论(最短路)+dp(记忆化搜索) 解题报告: 这题真的是个好东西! 做了这题我才发现我的dij一直是错的...但是我以前用dij做的题居然都A了?什么玄学事件啊...我哭了TT 不过其实感觉还 ...
- 洛谷P3953 逛公园(dp 拓扑排序)
题意 题目链接 Sol 去年考NOIP的时候我好像连最短路计数都不会啊qwq.. 首先不难想到一个思路,\(f[i][j]\)表示到第\(i\)个节点,与最短路之差长度为\(j\)的路径的方案数 首先 ...
- 洛谷 P3953 逛公园【spfa+记忆化dfs+bfs】
spfa预处理出最短路数组dis,然后反向建边bfs出ok[u]表示u能到n点 然后发现有0环的话时候有inf解的,先dfs找0环判断即可 然后dfs,设状态f[u][v]为到u点,还可以跑最短路+v ...
- 洛谷 P1053 逛公园 解题报告
P3953 逛公园 问题描述 策策同学特别喜欢逛公园. 公园可以看成一张\(N\)个点\(M\)条边构成的有向图,且没有自环和重边.其中1号点是公园的入口,\(N\)号点是公园的出口,每条边有一个非负 ...
- UVA 1400."Ray, Pass me the dishes!" -分治+线段树区间合并(常规操作+维护端点)并输出最优的区间的左右端点-(洛谷 小白逛公园 升级版)
"Ray, Pass me the dishes!" UVA - 1400 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...
随机推荐
- DIV+CSS初学随记
字间隔word-spacing 属性可以改变字(单词)之间的标准间隔.其默认值 normal 与设置值为 0 是一样的. word-spacing 属性接受一个正长度值或负长度值.如果提供一个正长度值 ...
- [JS设计模式]:构造函数模式(2)
基本用法 function Car(model, year, miles) { this.model = model; this.year = year; this.miles = miles; th ...
- 2019年度SAP项目实践计划
2019年度SAP项目实践计划 一晃2018年过去了,而新的一年说来就来了. 对于新的一年,笔者也难免有所畅想.早在上个月下旬就开始制定新年的诸多计划,比如写作计划,比如人工智能学习计划,比如新年度旅 ...
- Android Studio获取开发版SHA1值和发布版SHA1值的史上最详细方法
前言: 今天我想把百度地图的定位集成到项目中来,想写个小小的案例,实现一下,但在集成百度地图时首先要申请秘钥,申请秘钥要用到SHA1值,所以今天就来总结一下怎样去获取这个值吧,希望对大家有帮助. 正常 ...
- vue.js的手脚架vue-cli项目搭建的步骤
手脚架是什么? 众所周知,现在的前端项目发展得越渐越大,我们前端程序员要从0开始去搭建一套完整的项目很费时,所以这时候前端工程的手脚架就出现了. 我用得vue-cli也是其中之一,还有其他的我也说不清 ...
- PJSUA2开发文档--第十章 媒体质量(MEDIA QUALITY)
10 媒体质量(Media Quality) 10.1 音频质量 如果遇到音频质量问题,可尝试以下步骤: 遵循指南:使用pjsystest测试声音设备. 识别声音问题并使用以下步骤进行故障排除:检查声 ...
- MongoDB 中的【加减乘除】运算
很多同学因为对MongoDB不熟悉,加之应用的不是很多,有时候会认为MongoDB数据库对一些功能不支持,或者认为支持不好.今天我们 演示一下 MongoDB对“加减乘除”的使用. 在MongoDB数 ...
- Jenkins自动化部署-----持续交付【转】
感谢之前带领过我的leader,让我能够知道什么是好的开发方法. 在很早之前就接触过敏捷开发.什么是敏捷开发,简单来说就是让软件可靠地,快速地发布出来的一种开发方法和技巧. 而敏捷开发中有许多的实践, ...
- Linux学习历程——Centos 7 tar命令
一.命令介绍 tar命令用于对文件进行打包压缩或解压. tar常用参数 参数 作用 -c 创建压缩文件 -x 解开压缩文件 -t 查看压缩包内有哪些文件 -r 向压缩归档末尾追加文件 -u 更新压缩包 ...
- bootatrsp datetimepicker的初始化和阻止模态窗关闭(事件冒泡)
1.github下载资源包 http://www.bootcss.com/p/bootstrap-datetimepicker/ 2.引入bootstrap-datetimepicker.min.c ...