题目描述

策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从N号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N号点的最短路长为d,那么策策只会喜欢长度不超过d+K的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对P取模。

如果有无穷多条合法的路线,请输出−1。

输入输出格式

输入格式:

第一行包含一个整数 T, 代表数据组数。

接下来TT组数据,对于每组数据: 第一行包含四个整数 N,M,K,P,每两个整数之间用一个空格隔开。

接下来M行,每行三个整数ai​,bi​,ci​,代表编号为ai​,bi​的点之间有一条权值为 ci​的有向边,每两个整数之间用一个空格隔开。

输出格式:

输出文件包含 T 行,每行一个整数代表答案。

输入输出样例

输入样例#1:

2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
输出样例#1:

3
-1

说明

【样例解释1】

对于第一组数据,最短路为 33。 $1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5$ 为 33 条合法路径。

【测试数据与约定】

对于不同的测试点,我们约定各种参数的规模不会超过如下

测试点编号   TT    NN    MM    KK    是否有0边
1 5 5 10 0
2 5 1000 2000 0
3 5 1000 2000 50
4 5 1000 2000 50
5 5 1000 2000 50
6 5 1000 2000 50
7 5 100000 200000 0
8 3 100000 200000 50
9 3 100000 200000 50
10 3 100000 200000 50

对于 100%的数据, 1 \le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 10001≤P≤109,1≤ai​,bi​≤N,0≤ci​≤1000。

数据保证:至少存在一条合法的路线。

------------------------------------------------------

在此衷心感谢rockdu~

还是本着避开DP的原则,这一次我们继续用骚操作的避开一波浓浓的DP味~~~~

以下摘录rockdu的原话加上我的一点点理解:

首先这道题关键的一步是找出T到所有点的最短路是多少,

虽然起点很多但是终点只有一个,我们从终点反着跑最短路,就可以求出所有的最优距离。

然后我们想,如果从S出发到达点u,距离误差已经超过了K,这时候会怎么样呢?

我们无力回天,因为即使用最优策略也只能让误差不增加

所以对于每一个点,我们只关心误差在K以内的方案数

这时候统计方案数需要用到一个技巧,叫拆点最短路

对于每一个原图中的点,我们把它都拆成K个点,第x个点表示到了点u时误差为x的状态,也就是说强行把原来的走到u这个状态细化了,现在每一个小点能更精确的表示需要的信息

再进一步思考,这个图一定是一个dag:因为边权不为0,误差一定增大

那么想象一下,如果把小点从平面的图中拉出来

形成一层一层的结构,每一层都是一个x,那么一定是只能从x小的层向x大的层流动

也就是不可能一个点误差是k走一圈回来误差仍然是k,整个层次图构成了dag

因此,统计dag上可以到达T的路径数就可以了,写一个记忆化搜索做到O(n)  (我最后用的topsort+f[i]来解决这一个问题 topsort顺便用来判了-1的情况

如果有边权为0的,并且可以反向到达S正向到达T的环,那么有无限组方案

我觉得整个过程真的是妙妙啊....

同时要注意:

1.memset(first,0,sizeof(first));

2.根据新图的性质要把数组开到足够大

3.仔细品读建新图的过程

4.记得手写队列

以下代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define N 200100
#define ll long long
using namespace std;
int n,m,k,p;
ll ans;
struct node
{
int u,v,w,nxt;
}e[N*],g[N*];
int first[N],cnt;
void ade(int u,int v,int w)
{
e[++cnt].nxt=first[u]; first[u]=cnt;
e[cnt].u=u; e[cnt].v=v; e[cnt].w=w;
}
int fir[N*],cnnt;
void adde(int u,int v,int w)
{
g[++cnnt].nxt=fir[u]; fir[u]=cnnt;
g[cnnt].u=u; g[cnnt].v=v; g[cnnt].w=w;
}
void adeg(int u,int v)
{
g[++cnnt].nxt=fir[u]; fir[u]=cnnt;
g[cnnt].u=u; g[cnnt].v=v;
}
ll dis[N];
bool vis[N]; void spfa(int x)
{
queue<int>q;
memset(dis,0x3f,sizeof(dis));
memset(vis,true,sizeof(vis));
q.push(x);
dis[x]=;
while(!q.empty())
{
int u=q.front(); q.pop();
vis[u]=true;
for(int i=first[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(vis[v]==true)
{
q.push(v);
vis[v]=false;
}
}
}
}
}
ll dis2[N];
void spfa2(int x)
{
queue<int>q;
memset(dis2,0x3f,sizeof(dis));
memset(vis,true,sizeof(vis));
q.push(x);
dis2[x]=;
while(!q.empty())
{
int u=q.front(); q.pop();
vis[u]=true;
for(int i=fir[u];i;i=g[i].nxt)
{
int v=g[i].v;
if(dis2[v]>dis2[u]+g[i].w)
{
dis2[v]=dis2[u]+g[i].w;
if(vis[v]==true)
{
q.push(v);
vis[v]=false;
}
}
}
}
}
int get(int x,int y)
{
return (x-)*(k+)+y+;
}
int ru[N*];
void build_graph()
{
for(int i=;i<=m;i++)
{
int u=e[i].u,v=e[i].v,w=e[i].w;
int x=get(u,);
int y=get(v,dis[u]+w-dis[v]);
for(int j=dis[u];j+w+dis2[v]<=dis[n]+k;j++,x++,y++)
{ adeg(x,y); ru[y]++; }
}
}
ll sum,f[N*];
int q[N<<];
void topsort2()
{
int l = ,r=;
for(int i = ;i<=n*(k+);i++)
if(!ru[i]) q[++r]=i;
f[]=;
while(l<r)
{
int x=q[++l];
sum++;
for(int i=fir[x];i;i=g[i].nxt)
{
int v=g[i].v;
ru[v]--;
if(!ru[v]) q[++r]=v;
f[v]+=f[x];
f[v] = f[v]>p ? f[v]-p : f[v];
}
}
}
void pre()
{
memset(first,,sizeof(first));
memset(fir,,sizeof(fir));
memset(f,,sizeof(f));
memset(ru,,sizeof(ru));
sum=ans=cnnt=cnt=;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
pre();
scanf("%d%d%d%d",&n,&m,&k,&p);
for(int i=,x,y,z;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
ade(x,y,z); adde(y,x,z);
}
spfa();
spfa2(n);
memset(fir,,sizeof(fir));
cnnt=;
build_graph();
topsort2();
int num=(k+)*n;
if(sum<num) printf("-1\n");
else
{
for(int i=;i<=k;i++)
ans=(ans+f[get(n,i)])%p;
printf("%lld\n",ans);
}
}
return ;
}
/*
1
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
*/

我爱rockdu

【NOIP2017】逛公园 拆点最短路+拓扑(记忆化搜索的更多相关文章

  1. noip2017D1T3逛公园(拓扑图上dp,记忆化搜索)

    QWQ前几天才刚刚把这个D1T3写完 看着题解理解了很久,果然我还是太菜了QAQ 题目大意就是 给你一个n个点,m条边的图,保证1能到达n,求从1到n的 (设1到n的最短路长度是d)路径长度在[d,d ...

  2. [NOIP2017] 逛公园 (最短路,动态规划&记忆化搜索)

    题目链接 Solution 我只会60分暴力... 正解是 DP. 状态定义: \(f[i][j]\) 代表 \(1\) 到 \(i\) 比最短路长 \(j\) 的方案数. 那么很显然最后答案也就是 ...

  3. NOIP2017逛公园(dp+最短路)

    策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会 ...

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

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

  5. [luogu3952 noip2017] 逛公园 (计数dp+最短路)

    传送门 Description Input Output 输出文件包含 T 行,每行一个整数代表答案. Sample Input 2 5 7 2 10 1 2 1 2 4 0 4 5 2 2 3 2 ...

  6. P3183 [HAOI2016]食物链[拓扑/记忆化搜索]

    题目来源:洛谷 题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a ...

  7. 【比赛】NOIP2017 逛公园

    考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在 ...

  8. 【题解】NOIP2017逛公园(DP)

    [题解]NOIP2017逛公园(DP) 第一次交挂了27分...我是不是必将惨败了... 考虑这样一种做法,设\(d_i\)表示从该节点到n​节点的最短路径,\(dp(i,k)\)表示从\(i\)节点 ...

  9. [NOIP2017] 逛公园

    [NOIP2017] 逛公园 题目大意: 给定一张图,询问长度 不超过1到n的最短路长度加k 的1到n的路径 有多少条. 数据范围: 点数\(n \le 10^5\) ,边数\(m \le 2*10^ ...

随机推荐

  1. Spring的DI(Dependency Injection)

    写在之前,作为正在学习的程序员,对于Spring理解比较差,给两个简单的定义大家看一下. 控制反转(Inversion of Control),是一个重要的面向对象编程的法则来削减计算机程序的耦合问题 ...

  2. HDU 4741 Save Labman No.004 (几何)

    题意:求空间两线的最短距离和最短线的交点 题解: 线性代数和空间几何,主要是用叉积,点积,几何. 知道两个方向向量s1,s2,求叉积可以得出他们的公共垂直向量,然后公共垂直向量gamma和两线上的点形 ...

  3. lca(最近公共祖先(在线)) 倍增法详解

    转自大佬博客 : https://blog.csdn.net/lw277232240/article/details/72870644 描述:倍增法用于很多算法当中,通过字面意思来理解 LCA是啥呢 ...

  4. a survey for RL

    • A finite set of states St summarizing the information the agent senses from the environment at eve ...

  5. 什么是redis的持久化?

    什么是redis的持久化? RDB 持久化:该机制可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AOF 持久化:记录服务器执行的所有写操作命令,并在服 ...

  6. 119. Pascal's Triangle II@python

    Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle. Note t ...

  7. Windows 10 建立wifi热点

    如果当前是台式机那么需要一个usb的无线网卡,这里要注意如果你是使用台式机并且通过有线的方式上网,但是你的无线网卡适配器不能在禁用状态. 这里首先打开[运行]输入cmd,打开cmd(注意,这里要使用管 ...

  8. How To Add Swap Space on Ubuntu 16.04

    Introduction One of the easiest way of increasing the responsiveness of your server and guarding aga ...

  9. 基于Centos7.2使用Cobbler工具定制化批量安装Centos7.2系统

    1.1    定制Centos_7_x86_64.ks文件内容 # Cobbler for Kickstart Configurator for CentOS 7.2.1511 by Wolf_Dre ...

  10. 21.Yii2.0框架多表关联一对多查询之性能优化--模型的使用

    控制器里 功能: 通过分类,查分类下的所有文章 //关联查询 public function actionRelatesearch(){ //关联查询 //查询方法一(查一行) 一维数组下的值是obj ...