传送门

花了一个下午才 A 的毒瘤题

思路:

  这题需要建两个图,一个正向图,一个反向图。

  先在正向图上跑一遍 dijkstar ,计算出每个点到 点1 的最短路径 。

  然后在反向图上开始记忆化搜索:

  - 和动规一样,先定义 f [ i ][ j ] 表示:从 点 1 到 点 i 的距离为 dis [ i ] + j 的方案数。(初始值要为负,不然判断 0环 的时候会出错)

  - 对于每一条反向边(u,v,w)都有 f [ u ][ d ] = ∑ f [ u ][(dis[ u ] + d)-(dis[ v ] + w)] 。

    设 lck_dis = (dis[ u ] + d)-(dis[ v ] + w)。

    仔细分析会发现 lck_dis 就表示 点 u 到 起点 1 的距离。

    这类似于 最短路计数 的转移,因为建的是反向边,所以要从后往前转移。

  - 为了判断是否有毒瘤的 0边,需要开一个布尔数组 flag [ i ][ j ] 判断 dp 值是否被经过 2 次,且没有被确定,那么一定是有 0边 导致的自环。

Code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<string>
#include<stack>
#include<vector>
#include<queue>
#include<deque>
#include<map>
#include<set>
using namespace std;
#define INF 0x3f
const int maxn=1e5+;
inline int read()
{
int xs=,kr=;
char ls;
ls=getchar();
while(!isdigit(ls))
{
if(ls=='-')
kr=-;
ls=getchar();
}
while(isdigit(ls))
{
xs=(xs<<)+(xs<<)+(ls^);
ls=getchar();
}
return xs*kr;
}
int T,n,m,k,p;
long long ans;
int head_dij[maxn],head_dfs[maxn],dis[maxn],f[maxn][];
bool bo,vis[maxn],flag[maxn][];
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q;
struct hh
{
int nex,to,w;
} t_dij[maxn<<],t_dfs[maxn<<];
inline void clear()
{
bo=false;
memset(head_dij,,sizeof(head_dij));
memset(head_dfs,,sizeof(head_dfs));
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
memset(f,-,sizeof(f));
}
inline void add(int cnt,int nex,int to,int w)
{
t_dij[cnt].to=to; t_dij[cnt].w=w;
t_dij[cnt].nex=head_dij[nex]; head_dij[nex]=cnt; t_dfs[cnt].to=nex; t_dfs[cnt].w=w;
t_dfs[cnt].nex=head_dfs[to]; head_dfs[to]=cnt;
}
inline void dijkstra(int s)
{
dis[s]=;
q.push(make_pair(,s));
while (!q.empty())
{
int u=q.top().second;
q.pop();
if (vis[u]) continue;
vis[u]=true;
for (int i=head_dij[u];i;i=t_dij[i].nex)
{
int v=t_dij[i].to,w=t_dij[i].w;
if (!vis[v]&&dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
q.push(make_pair(dis[v],v));
}
}
}
}
int dfs(int u,int d)
{
if (flag[u][d])
{
bo=true;
return ;
}
if (~f[u][d]) return f[u][d];
flag[u][d]=true;f[u][d]=;
for (int i=head_dfs[u];i;i=t_dfs[i].nex)
{
if(bo) break;
int v=t_dfs[i].to,w=t_dfs[i].w;
int lck_dis=(dis[u]+d)-(w+dis[v]);
if (lck_dis>=) f[u][d]=(f[u][d]+dfs(v,lck_dis))%p;
}
flag[u][d]=false;
if (u==&&!d) return ++f[u][d];
return f[u][d];
}
int x,y,z;
int main()
{
//freopen("park.in","r",stdin);
//freopen("park.out","w",stdout);
T=read();
while (T--)
{
clear();
n=read();m=read();k=read();p=read();
for(int i=;i<=m;i++)
{
x=read();y=read();z=read();
add(i,x,y,z);
}
dijkstra();
ans=dfs(n,)%p;
for(int i=;i<=k;i++)
{
if(bo) break;
ans=(ans+dfs(n,i))%p;
}
if(bo) printf("-1\n");
else printf("%lld\n",ans);
}
return ;
}

注:在 dfs 中,if ( ~ f [ u ][ d ] ) ⇔ if ( f [ u ][ d ] ≥ 0 ) 。有助于卡常

P3953 逛公园的更多相关文章

  1. P3953 逛公园(dp,最短路)

    P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经 ...

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

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

  3. [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)

    题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...

  4. LOJ P3953 逛公园 NOIP dp 最短路 拓扑排序

    https://www.luogu.org/problemnew/show/P3953 开o2过了不开o2re一个点...写法如题 顺便一提这道题在我校oj是a不了的因为我校土豆服务器速度奇慢1s时限 ...

  5. 【luogu P3953 逛公园】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3953 题外话:感觉2017年神题好多..这还不是最神的一道,真在考场上我也就写个最短路计数暴力了.现在在大佬 ...

  6. 洛谷P3953逛公园

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

  7. 洛谷 P3953 逛公园

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

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

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

  9. Luogu P3953 逛公园

    不管怎么说,这都是一道十分神仙的NOIp题 你可以说它狗,但不可以否认它就是NOIp的难度 首先这道题很显然是道图论题还是一道图论三合一(最短路+拓扑+图上DP) 先考虑最短路,我们分别以\(1\)和 ...

随机推荐

  1. vi命令设置行号

    1. :set nu :显示行号

  2. Mysql8安装与配置

    网上的教程有很多,基本上大同小异.但是安装软件有时就可能因为一个细节安装失败.我也是综合了很多个教程才安装好的,所以本教程可能也不是普遍适合的. 安装环境:win7 1.下载zip安装包: MySQL ...

  3. Redis和mysql数据怎么保持数据一致的?

    需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库.   这个业务场景, ...

  4. mybatis增强

    MyBatis SQL参数传递(掌握) SQL映射器Mapper接口(掌握)Myb atis批量操作(理解掌握) (多对一)关联映射(掌握) (一对多,多对多)集合映射 MyBatis原理回顾(Obj ...

  5. Fiddler抓包【2】_捕获设置

    1.Fiddler抓web网站请求 手动设置方法一:Tools--->WinINET Options--->连接--->局域网设置--->代理服务器勾选后“高级”---> ...

  6. SQL- 行转列,多行转多列 - max 函数

    效果如图,把同一个 code, 按 cate 列相同行的进行合并后分两行,把mode 每种类型转换成 列名 ,主要用到了 max 函数,很实用 if exists(select * from temp ...

  7. linux上的图片查看器FEH_image_view

    Linux上的图片查看器, 简单,没有多余功能,打开快速,体积小 在终端用feh # 直接执行feh显示当前目录所有图片 feh # 或者指定图片名 feh pic1 pic2 pic3 # 显示一个 ...

  8. Roomblock: a Platform for Learning ROS Navigation With Roomba, Raspberry Pi and RPLIDAR(转)

      What is this? "Roomblock" is a robot platform consists of a Roomba, a Raspberry Pi 2, a ...

  9. 一个handle使用更新线程的实例

    handle更新线程实例 package com.example.administrator.handle; import android.app.Activity;import android.os ...

  10. LR12中针对WebServices协议的三种脚本开发模式

    一,webservices协议简介 webservices是建立可交互操作的分布式应用程序的新平台,它通过一系列的标准和协议来保证程序之间的动态连接, 其中最基本的协议包括soap,wsdl,uddi ...