题目描述

策策同学特别喜欢逛公园。公园可以看成一张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.记得手写队列

以下代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<queue>
  7 #define N 200100
  8 #define ll long long
  9 using namespace std;
 10 int n,m,k,p;
 11 ll ans;
 12 struct node
 13 {
 14     int u,v,w,nxt;
 15 }e[N*2],g[N*53];
 16 int first[N],cnt;
 17 void ade(int u,int v,int w)
 18 {
 19     e[++cnt].nxt=first[u]; first[u]=cnt;
 20     e[cnt].u=u; e[cnt].v=v; e[cnt].w=w;
 21 }
 22 int fir[N*53],cnnt;
 23 void adde(int u,int v,int w)
 24 {
 25     g[++cnnt].nxt=fir[u]; fir[u]=cnnt;
 26     g[cnnt].u=u; g[cnnt].v=v; g[cnnt].w=w;
 27 }
 28 void adeg(int u,int v)
 29 {
 30     g[++cnnt].nxt=fir[u]; fir[u]=cnnt;
 31     g[cnnt].u=u; g[cnnt].v=v;
 32 }
 33 ll dis[N];
 34 bool vis[N];
 35
 36 void spfa(int x)
 37 {
 38     queue<int>q;
 39     memset(dis,0x3f,sizeof(dis));
 40     memset(vis,true,sizeof(vis));
 41     q.push(x);
 42     dis[x]=0;
 43     while(!q.empty())
 44     {
 45         int u=q.front(); q.pop();
 46         vis[u]=true;
 47         for(int i=first[u];i;i=e[i].nxt)
 48         {
 49             int v=e[i].v;
 50             if(dis[v]>dis[u]+e[i].w)
 51             {
 52                 dis[v]=dis[u]+e[i].w;
 53                 if(vis[v]==true)
 54                 {
 55                     q.push(v);
 56                     vis[v]=false;
 57                 }
 58             }
 59         }
 60     }
 61 }
 62 ll dis2[N];
 63 void spfa2(int x)
 64 {
 65     queue<int>q;
 66     memset(dis2,0x3f,sizeof(dis));
 67     memset(vis,true,sizeof(vis));
 68     q.push(x);
 69     dis2[x]=0;
 70     while(!q.empty())
 71     {
 72         int u=q.front(); q.pop();
 73         vis[u]=true;
 74         for(int i=fir[u];i;i=g[i].nxt)
 75         {
 76             int v=g[i].v;
 77             if(dis2[v]>dis2[u]+g[i].w)
 78             {
 79                 dis2[v]=dis2[u]+g[i].w;
 80                 if(vis[v]==true)
 81                 {
 82                     q.push(v);
 83                     vis[v]=false;
 84                 }
 85             }
 86         }
 87     }
 88 }
 89 int get(int x,int y)
 90 {
 91     return (x-1)*(k+1)+y+1;
 92 }
 93 int ru[N*53];
 94 void build_graph()
 95 {
 96     for(int i=1;i<=m;i++)
 97     {
 98         int u=e[i].u,v=e[i].v,w=e[i].w;
 99         int x=get(u,0);
100         int y=get(v,dis[u]+w-dis[v]);
101         for(int j=dis[u];j+w+dis2[v]<=dis[n]+k;j++,x++,y++)
102         { adeg(x,y); ru[y]++; }
103     }
104 }
105 ll sum,f[N*53];
106 int q[N<<6];
107 void topsort2()
108 {
109     int l = 0,r=0;
110     for(int i = 1;i<=n*(k+1);i++)
111         if(!ru[i]) q[++r]=i;
112     f[1]=1;
113     while(l<r)
114     {
115         int x=q[++l];
116         sum++;
117         for(int i=fir[x];i;i=g[i].nxt)
118         {
119             int v=g[i].v;
120             ru[v]--;
121             if(!ru[v]) q[++r]=v;
122             f[v]+=f[x];
123             f[v] = f[v]>p ? f[v]-p : f[v];
124         }
125     }
126 }
127 void pre()
128 {
129     memset(first,0,sizeof(first));
130     memset(fir,0,sizeof(fir));
131     memset(f,0,sizeof(f));
132     memset(ru,0,sizeof(ru));
133     sum=ans=cnnt=cnt=0;
134 }
135 int main()
136 {
137     int t;
138     scanf("%d",&t);
139     while(t--)
140     {
141         pre();
142         scanf("%d%d%d%d",&n,&m,&k,&p);
143         for(int i=1,x,y,z;i<=m;i++)
144         {
145             scanf("%d%d%d",&x,&y,&z);
146             ade(x,y,z); adde(y,x,z);
147         }
148         spfa(1);
149         spfa2(n);
150         memset(fir,0,sizeof(fir));
151         cnnt=0;
152         build_graph();
153         topsort2();
154         int num=(k+1)*n;
155         if(sum<num) printf("-1\n");
156         else
157         {
158             for(int i=0;i<=k;i++)
159                 ans=(ans+f[get(n,i)])%p;
160             printf("%lld\n",ans);
161         }
162     }
163     return 0;
164 }
165 /*
166 1
167 5 7 2 10
168 1 2 1
169 2 4 0
170 4 5 2
171 2 3 2
172 3 4 1
173 3 5 2
174 1 5 3
175 */

我爱rockdu

转载于:https://www.cnblogs.com/kylara/p/9748884.html

【NOIP2017】逛公园 拆点最短路+拓扑(记忆化搜索相关推荐

  1. NOIP 2017 逛公园 记忆化搜索 最短路 好题

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

  2. NOIP2017 逛公园

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

  3. 洛谷3953 (NOIp2017) 逛公园——记忆化搜索+用栈判0环

    题目:https://www.luogu.org/problemnew/show/P3953 因为K只有50,所以想到用dp[ cr ][ j ]表示在点cr.比最短路多走了 j 的方案数.(看了TJ ...

  4. [NOIP2017]逛公园 最短路+拓扑排序+dp

    题目描述 给出一张 $n$ 个点 $m$ 条边的有向图,边权为非负整数.求满足路径长度小于等于 $1$ 到 $n$ 最短路 $+k$ 的 $1$ 到 $n$ 的路径条数模 $p$ ,如果有无数条则输出 ...

  5. [NOIP2017]逛公园

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

  6. NOIP2017逛公园

    在WA了接近20遍后,本蒟蒻终于切掉了逛公园.. 逛公园的题意为求出图中从1到n路径长度<=d(最短路)+k 的 路径条数. 这道题十分的像luogu 1608 路径统计,虽然算法完全不一样, ...

  7. LOJ #2316「NOIP2017」逛公园【最短路】【记忆化搜索】

    dis[i]dis[i]dis[i]表示111号点到iii号点的最短距离,用spfaspfaspfa跑一遍即可. 考虑如何设定状态. 注意到题意要的是小于等于dis[n]+Kdis[n]+Kdis[n ...

  8. NOIP2017 逛公园(最短路+记忆化搜索)

    Description Input Output Example input 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 ...

  9. CCF CSP 点亮数字人生(记忆化搜索+拓扑排序判环)

    题目背景 土豪大学的计算机系开了一门数字逻辑电路课,第一个实验叫做"点亮数字人生",要用最基础的逻辑元件组装出实际可用的电路.时间已经是深夜了,尽管实验箱上密密麻麻的连线已经拆装了 ...

最新文章

  1. 2021机器智能研究方向
  2. 浅谈Web中前后端模板引擎的使用
  3. 转: Python集合(set)类型的操作
  4. Vue+Openlayers显示TileWMS时不显示默认控件放大缩小旋转等组件
  5. 消息中间件(Kafka/RabbitMQ)收录集
  6. jpa 实体映射视图_JPA教程:实体映射-第2部分
  7. Swing应用程序中的CDI事件可将UI与事件处理分离
  8. 如何规划前端工程师职业发展路线?
  9. informix使用得一些小常识
  10. 数字频率计的Verilog设计
  11. “刀片嗓”“水泥鼻”“咳出肺”可以这样缓解!
  12. 日期计算excel_在Excel中计算日期范围内的项目
  13. 果壳格言——偶像的力量近在眼前
  14. ZUCC_计算机系统原理实验_大作业 bomb 破解
  15. BUUCTF 喵喵喵
  16. 从无到有学习物联网00-千里之行始于足下
  17. 老北京人推荐的50个秘境景点
  18. DataFram列操作_withColumn()
  19. image居中、div嵌套div上下左右居中
  20. 如何应用北极星指标体系?

热门文章

  1. 【腾讯Bugly干货分享】彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法
  2. 制作和unity调用动态链接库dll文件
  3. USACO3.22Stringsobits
  4. Report Style
  5. Close window without alert
  6. “先粗后精”的实例分割,BPR:使用Crop-then-Refine的性能提高方法
  7. 行人重识别的挑战与最新进展(35页PPT整理)
  8. 百度AI快车道深圳专场,揭秘CV目标检测核心技术
  9. ICCV NAS Workshop 最佳论文提名:通过层级掩码实现高效神经网络架构搜索
  10. 资深程序员才知道的30个Python技巧