luogu 3953 逛公园

noip2017 D1T3 逛公园 某zz选手看到数据范围直接就最短路计数了,结果写错了爆零

题目大意:

N个点M条边构成的有向图,且没有自环和重边。其中1号点是起点,N号点是公园的终点,每条边有一个非负权值, 代表经过这条边所要花的时间

如果1号点到N号点的最短路长为d,那么策策只选择长度不超过d + K的路线

求总共有多少条满足条件的路线

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

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

思路:

首先需要求出最短路用spfa

然后我们dfs的时候dp

具体见注释

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstdlib>
 5 #include<cstring>
 6 #include<algorithm>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 2139062143
10 #define ll long long
11 #define MAXN 100100
12 using namespace std;
13 inline int read()
14 {
15     int x=0,f=1;char ch=getchar();
16     while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
17     while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();}
18     return x*f;
19 }
20 int T,n,m,k,MOD;
21 int cnt,nxt[MAXN*2],fst[MAXN],to[MAXN*2],val[MAXN*2];
22 int Cnt,Nxt[MAXN*2],Fst[MAXN],To[MAXN*2],Val[MAXN*2];
23 int dis[MAXN],dp[MAXN][55];
24 bool vis[MAXN],jdg[MAXN][55],f;
25 void add(int u,int v,int w) {nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
26 void Add(int u,int v,int w) {Nxt[++Cnt]=Fst[u],Fst[u]=Cnt,To[Cnt]=v,Val[Cnt]=w;}
27 void spfa()
28 {
29     memset(dis,127,sizeof(dis));
30     queue <int> q;
31     dis[1]=0,vis[1]=1;q.push(1);
32     while(!q.empty())
33     {
34         int k=q.front();
35         q.pop();vis[k]=0;
36         for(int i=fst[k];i;i=nxt[i])
37             if(dis[k]+val[i]<dis[to[i]]) {dis[to[i]]=dis[k]+val[i];if(!vis[to[i]]){vis[to[i]]=1;q.push(to[i]);}}
38     }
39 }
40 int dfs(int x,int ext)//表示走到x节点刚好多走了ext dfs的时候按照反向边走
41 {
42     if(dp[x][ext]!=-1) return dp[x][ext];
43     jdg[x][ext]=1,dp[x][ext]=0;//jdg用来判零环 (如果一个点相同的ext在dp还未被确定的情况下被访问了两遍,说明有零环)
44     for(int i=Fst[x];i;i=Nxt[i])
45     {
46         if(dis[x]-dis[To[i]]+ext-Val[i]<0) continue;//这么长的一大串表示按这条边走的ext <0说明不能按这条边走
47         if(jdg[To[i]][dis[x]-dis[To[i]]+ext-Val[i]]) f=1;//有零环
48         (dp[x][ext]+=dfs(To[i],dis[x]-dis[To[i]]+ext-Val[i]))%=MOD;//接着dfs
49     }
50     jdg[x][ext]=0;
51     return dp[x][ext];
52 }
53 int main()
54 {
55     T=read();
56     int a,b,c,ans=0;
57     while(T--)
58     {
59         memset(nxt,0,sizeof(nxt));
60         memset(Nxt,0,sizeof(Nxt));
61         memset(Fst,0,sizeof(Fst));
62         memset(fst,0,sizeof(fst));
63         memset(jdg,0,sizeof(jdg));
64         memset(vis,0,sizeof(vis));
65         memset(dp,0xff,sizeof(dp));//设为-1是因为在这个dp里 0也是一种合法的结果
66         n=read(),m=read(),k=read(),MOD=read(),cnt=Cnt=0;
67         for(int i=1;i<=m;i++) {a=read(),b=read(),c=read();add(a,b,c);Add(b,a,c);}
68         spfa();//处理出最短路
69         ans=f=0,dp[1][0]=1;
70         for(int i=0;i<=k;i++) (ans+=dfs(n,i))%=MOD;//倒着dfs 在搜索的过程中能够非常巧妙地判断零环
71         dfs(n,k+1);//用来判断k==0时有零环的情况
72         if(f) puts("-1");
73         else printf("%d\n",ans);
74     }
75 }

时间: 2024-08-29 17:30:55

luogu 3953 逛公园的相关文章

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

题面 传送门:https://www.luogu.org/problemnew/show/P3953 Solution 这是一道神题 首先,我们不妨想一下K=0,即求最短路方案数的部分分. 我们很容易可以想到一个做法,就是魔改迪杰斯特拉做法: 如果一个点可以更新到达其他点的距离,那个点的方案数就是这个点的方案数:如果一个点所更新出来的距离和之前的相等,那个点的方案数加等当前点的方案数. 用式子可以表现为: f[j]=f[i] (dis[j]>dis[i]+x)   f[j]+=f[i] (dis

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

P3953 逛公园 题面 题目描述 策策同学特别喜欢逛公园.公园可以看成一张 \(N\) 个点 \(M\) 条边构成的有向图,且没有自环和重边.其中 \(1\) 号点是公园的入口,\(N\) 号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从 \(1\) 号点进去,从 \(N\) 号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果 \(

洛谷3953:逛公园——题解

https://www.luogu.org/problemnew/show/P3953 策策同学特别喜欢逛公园.公园可以看成一张n个点m条边构成的有向图,且没有自环和重边.其中1号点是公园的入口,n号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从n号点出来. 策策喜欢新鲜的事物,他不希望有两天逛公园的路线完全一样,同时策策还是一个特别热爱学习的好孩子,他不希望每天在逛公园这件事上花费太多的时间.如果1号点到n号点的最短路长为d

Luogu P3953【NOIP2017】逛公园【最短路+拓扑排序+动态规划】

题目描述 策策同学特别喜欢逛公园.公园可以看成一张NN个点MM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从NN号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线. 策策

TYVJ1427 小白逛公园

P1427 小白逛公园 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 小新经常陪小白去公园玩,也就是所谓的遛狗啦…在小新家附近有一条“公园路”,路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了.    一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的一些公园玩.小白当然希望选出的公园的分数总和尽量高咯

线段树--小白逛公园nkoj1316

小白逛公园 Time Limit:20000MS  Memory Limit:65536K Case Time Limit:2000MS Description 小新经常陪小白去公园玩,也就是所谓的遛狗啦-在小新家附近有一条"公园路",路的一边从南到北依次排着n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了. 一开始,小白就根据公园的风景给每个公园打了分-.-.小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第a个和第b个公园之间(包括a.b两个公园)选择连续的

NOIP2017D1T3逛公园——哎呦!

#include<cstdio> #include<cstring> #define MXN 100001 #define MXM 200001 #define MXK 51 int afst[MXM],anxt[MXM],av[MXM],aw[MXM]; int bfst[MXM],bnxt[MXM],bv[MXM],bw[MXM]; int dis[MXN],queue[10*MXN]; int f[MXN][MXK],vis[MXN][MXK]; int n,m,k,p,t,

【比赛】NOIP2017 逛公园

考试的时候灵光一闪,瞬间推出DP方程,但是不知道怎么判-1,然后?然后就炸了. 后来发现,我只要把拓扑和DP分开,中间加一个判断,就AC了,可惜. 看这道题,我们首先来想有哪些情况是-1:只要有零环在满足题目要求的路径上,那么这条路径就可以不停地走,于是就-1了. 如何判有没有零环呢? 机械化地两遍不同方向的SPFA,就知道某个点在不在最短路上,以此建一个最短路图,在最短路图上找零环.于是就拓扑啦.稍加判断就解决了整个题目最关键的-1. 接下来就是DP了,设f[i][j]表示走到i点,走过路程已

[NOIp 2017]逛公园

Description 策策同学特别喜欢逛公园.公园可以看成一张$N$个点$M$条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,$N$号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间. 策策每天都会去逛公园,他总是从1号点进去,从$N$号点出来. 策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间.如果1号点 到$N$号点的最短路长为$d$,那么策策只会喜欢长度不超过$d