洛谷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 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...
随机推荐
- Android为TV端助力 ViewTreeObserver(转载)
Android ViewTreeObserver简介 一.结构 public final class ViewTreeObserver extends Object java.lang.Objec ...
- HttpWebRequest 改为 HttpClient 踩坑记-请求头设置
HttpWebRequest 改为 HttpClient 踩坑记-请求头设置 Intro 这两天改了一个项目,原来的项目是.net framework 项目,里面处理 HTTP 请求使用的是 WebR ...
- asyncio异步IO--协程(Coroutine)与任务(Task)详解
摘要:本文翻译自Coroutines and Tasks,主要介绍asyncio中用于处理协程和任务的方法和接口.在翻译过程中,译者在官方文档的基础上增加了部分样例代码和示意图表,以帮助读者对文档的理 ...
- SQL Server 索引碎片产生原理重建索引和重新组织索引
数据库存储本身是无序的,建立了聚集索引,会按照聚集索引物理顺序存入硬盘.既键值的逻辑顺序决定了表中相应行的物理顺序 多数情况下,数据库读取频率远高于写入频率,索引的存在 为了读取速度牺牲写入速度 页 ...
- Linux 通过编译安装apache服务以及配置
Linux 编译安装apache服务 一.安装 1.通过编译安装,首先需要下载源代码安装包 apache下载链接:http://httpd.apache.org/download.cgi 2.解开源代 ...
- Django REST framework基础:版本控制
DRF的版本控制 为什么需要版本控制 API 版本控制允许我们在不同的客户端之间更改行为(同一个接口的不同版本会返回不同的数据). DRF提供了许多不同的版本控制方案. 可能会有一些客户端因为某些原因 ...
- HTMLCSS--案例| 超链接美化 | 模态框 | tab栏选项卡
一.超链接美化 二.模态框 三.tab栏选项卡 -------------------------------------------- 一.超链接美化 <!DOCTYPE html> & ...
- 【Python 补充01】Python运算符
Python运算符 举个简单的例子 4 +5 = 9 . 例子中,4 和 5 被称为操作数,"+" 称为运算符. 1.算术运算符 + - * / # 加减乘除 % # 取模(返回除 ...
- HBase2.0中的Benchmark工具 — PerformanceEvaluation
简介 在项目开发过程中,我们经常需要一些benchmark工具来对系统进行压测,以获得系统的性能参数,极限吞吐等等指标. 而在HBase中,就自带了一个benchmark工具—PerformanceE ...
- solr 7.7 搭建和搜索
最近做了个solr搜索的demo, 用的是solr7.7,之前网上好多文章搭建solr都是5.5+tomcat.. 自己摆弄了下,发现solr7.7和5.5 的部分文件夹有些改动,没有深究原理也就没有 ...