P3953 逛公园
传送门
花了一个下午才 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 逛公园的更多相关文章
- P3953 逛公园(dp,最短路)
P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经 ...
- Luogu P3953 逛公园(最短路+记忆化搜索)
P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公 ...
- [Luogu P3953] 逛公园 (最短路+拓扑排序+DP)
题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易 ...
- LOJ P3953 逛公园 NOIP dp 最短路 拓扑排序
https://www.luogu.org/problemnew/show/P3953 开o2过了不开o2re一个点...写法如题 顺便一提这道题在我校oj是a不了的因为我校土豆服务器速度奇慢1s时限 ...
- 【luogu P3953 逛公园】 题解
题目链接:https://www.luogu.org/problemnew/show/P3953 题外话:感觉2017年神题好多..这还不是最神的一道,真在考场上我也就写个最短路计数暴力了.现在在大佬 ...
- 洛谷P3953逛公园
题目 作为\(NOIp2017D1T3\) 这个题还是很良心的,至少相对于\(NOIp2018\)来说,希望\(NOIp2019\)不会这么坑吧. 这个题可以作为记忆化搜索的进阶题了,做这个题的方法也 ...
- 洛谷 P3953 逛公园
题目链接 思路 首先没有0边,且k为0的情况就是最短路计数. 如果k不为0,看到k<=50,想到dp. 设f[u][i]表示到达u点比最短路多走i的路径数,转移到v点. f[u][i]+=f[v ...
- 洛谷P3953 逛公园(NOIP2017)(最短/长路,拓扑排序,动态规划)
洛谷题目传送门 又是一年联赛季.NOIP2017至此收官了. 这个其实是比较套路的图论DP了,但是细节有点恶心. 先求出\(1\)到所有点的最短路\(d1\),和所有点到\(n\)的最短路\(dn\) ...
- Luogu P3953 逛公园
不管怎么说,这都是一道十分神仙的NOIp题 你可以说它狗,但不可以否认它就是NOIp的难度 首先这道题很显然是道图论题还是一道图论三合一(最短路+拓扑+图上DP) 先考虑最短路,我们分别以\(1\)和 ...
随机推荐
- C# 字典Dictionary
Dictionary<TKey, TValue> 泛型类提供了从一组键到一组值的映射.通过键来检索值的速度是非常快的,接近于 O(1),这是因为 Dictionary<TKey, T ...
- 从合并两个Map说开去 - foldLeft 和 foldRight 还有模式匹配
开发中遇到需求:合并两个Map集合对象(将两个对应Key的值累加) 先说解决方案: ( map1 /: map2 ) { )) ) } 首先: Scala中现有的合并集合操作不能满足这个需求 . 注意 ...
- python迭代-如何实现反向迭代
如何实现反向迭代 问题举例 实现一个连续浮点数发生器FloatRange,根据给定范围(start, end)和步进值(step) 产生一系列连续的浮点数,如FloatRange(3.0, 4.0, ...
- 又见thrift异常之TApplicationException: Internal error processing..
客户端调用获取商户提现产品手续费的接口,出现异常org.apache.thrift.TApplicationException: Internal error processing getMercha ...
- 关于UR=A的测试
当数据库在nomount,mount或者restricted这类特殊状态下,同时动态监听显示状态为BLOCKED,客户端无法直接连接到实例,此时可通过配置UR=A进行连接.最常见的场景就是10g版本的 ...
- TCP 数据传输工具类
package com.ivchat.test.propertysystem.util; import java.io.BufferedReader;import java.io.ByteArrayO ...
- git上clone需要ssh时
在命令行中输入ssh-keygen -t rsa -C "your_email@example.com" 然后使用编辑器打开id_rsa.pub文件,复制里面的ssh
- PostgreSQL 9.5.x的架构图及外存图
- python值json与pickle模块
#json 是用来序列化对象的 # 只有2个方法,序列化与反序列化 # 但是不能序列化类 与 函数 import json dict={"key1":[1,2,3,4,5]} f ...
- Vue系列之 => webpack-babel的配置
安装 cnpm i babel-core@6.26.3 babel-loader@7.0.0 babel-plugin-transform-runtime -D cnpm i babel-preset ...