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
",ans);
74     }
75 }
View Code
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/8000123.html