【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)

题意:

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

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

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

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

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

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

n<=1e5,m<=2e5,K<=50,1≤P≤1e9,0≤ci≤1000。

思路:因为K很小,建立以1为源点的最短路图,在最短路图上进行DP计数

dp[i][j]表示当前在点i,比最短路线多走j时间的方案数

在1到N的最短路上可能有环,这样会出现-1的情况,同时还有边长为0的存在,这两个问题都可以使用拓扑排序解决

对于-1拓扑排序后直接判断

对于边长为0按照拓扑序进行转移

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<map>
  8 #include<set>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 typedef long long ll;
 13 typedef unsigned int uint;
 14 typedef unsigned long long ull;
 15 typedef pair<int,int> PII;
 16 typedef vector<int> VI;
 17 #define fi first
 18 #define se second
 19 #define MP make_pair
 20 #define N   110000
 21 #define M   210000
 22 #define eps 1e-8
 23 #define pi acos(-1)
 24 priority_queue<pair<int,int> > q;
 25  
 26 int dp[N][51],head[M],vet[M],nxt[M],len[M],head2[M],vet2[M],nxt2[M],len2[M],
 27     dis[N],dis2[N],vis[N],p[N],d[N],tot,tot2;
 28     
 29 void add(int a,int b,int c)
 30 {
 31     nxt[++tot]=head[a];
 32     vet[tot]=b;
 33     len[tot]=c;
 34     head[a]=tot;
 35 }
 36 
 37 void add2(int a,int b,int c)
 38 {
 39     nxt2[++tot2]=head2[a];
 40     vet2[tot2]=b;
 41     len2[tot2]=c;
 42     head2[a]=tot2;
 43 }
 44 
 45 int main()
 46 {
 47     //freopen("uoj331.in","r",stdin);
 48   //  freopen("uoj331.out","w",stdout);
 49     int cas;
 50     scanf("%d",&cas);
 51     for(int v1=1;v1<=cas;v1++)
 52     {
 53         int n,m,K,MOD;
 54         scanf("%d%d%d%d",&n,&m,&K,&MOD);
 55         tot=tot2=0;
 56         memset(head,0,sizeof(head));
 57         memset(head2,0,sizeof(head2));
 58         for(int i=1;i<=m;i++)
 59         {
 60             int x,y,z;
 61             scanf("%d%d%d",&x,&y,&z);
 62             add(x,y,z);
 63             add2(y,x,z);
 64         }
 65         //printf("readend
"); 
 66         memset(vis,0,sizeof(vis));
 67            memset(dis,0x3f,sizeof(dis));
 68         memset(d,0,sizeof(d));
 69         q.push(MP(0,1)); dis[1]=0;
 70         while(!q.empty())
 71         {
 72             int u=q.top().se; 
 73             q.pop();
 74             if(vis[u]) continue;
 75             vis[u]=1;
 76             int e=head[u];
 77             while(e)
 78             {
 79                 int v=vet[e];
 80                 if(dis[u]+len[e]<dis[v])
 81                 {
 82                     dis[v]=dis[u]+len[e];
 83                     q.push(MP(-dis[v],v));
 84                 }
 85                 e=nxt[e];
 86             }
 87         }
 88         //printf("dijk1end
");
 89         memset(vis,0,sizeof(vis));
 90         memset(dis2,0x3f,sizeof(dis2));
 91         q.push(MP(0,n)); dis2[n]=0;
 92         while(!q.empty())
 93         {
 94             int u=q.top().se;
 95             q.pop();
 96             if(vis[u]) continue;
 97             vis[u]=1;
 98             int e=head2[u];
 99             while(e)
100             {
101                 int v=vet2[e];
102                 if(dis2[u]+len2[e]<dis2[v])
103                 {
104                     dis2[v]=dis2[u]+len2[e];
105                     q.push(MP(-dis2[v],v));
106                 }
107                 e=nxt2[e];
108             }
109         }
110         //printf("dijk2end
");
111         for(int i=1;i<=n;i++)
112         {
113             int e=head[i];
114             while(e)
115             {
116                 int v=vet[e];
117                 if(dis[i]+len[e]==dis[v]) d[v]++;
118                 e=nxt[e];
119             }
120         }
121         tot=0;
122         for(int i=1;i<=n;i++)
123          if(!d[i]) p[++tot]=i;
124         //printf("%d
",tot);
125         for(int i=1;i<=tot;i++)
126         {
127             int u=p[i];
128             int e=head[u];
129             while(e)
130             {
131                 int v=vet[e];
132                 if(dis[u]+len[e]==dis[v])
133                 {
134                     d[v]--;
135                     if(!d[v]) p[++tot]=v;
136                 }
137                 e=nxt[e];
138             }
139         }
140         //printf("topoend
");
141         int flag=1;
142         for(int i=1;i<=n;i++)
143          if(d[i]&&dis[i]+dis2[i]<=dis[n]+K)
144          {
145              printf("-1
");
146              flag=0;
147              break;
148          }
149         if(!flag) continue;
150         memset(dp,0,sizeof(dp));
151         dp[1][0]=1;
152         for(int k=0;k<=K;k++)
153         {
154             for(int i=1;i<=tot;i++)
155             {
156                 int u=p[i];
157                 int e=head[u];
158                 while(e)
159                 {
160                     int v=vet[e];
161                     if(dis[u]+len[e]==dis[v]) dp[v][k]=(dp[v][k]+dp[u][k])%MOD;
162                     e=nxt[e];
163                 }
164             }
165             
166             for(int i=1;i<=n;i++)
167             {
168                 int e=head[i];
169                 while(e)
170                 {
171                     int v=vet[e];
172                     int t=k+dis[i]+len[e]-dis[v]; 
173                      if(dis[i]+len[e]!=dis[v]&&t<=K) dp[v][t]=(dp[v][t]+dp[i][k])%MOD;
174                     e=nxt[e];
175                 }
176             }
177         }
178         ll ans=0;
179         for(int i=0;i<=K;i++) ans=(ans+dp[n][i])%MOD;
180         printf("%lld
",ans);
181     }
182     return 0;
183 }
原文地址:https://www.cnblogs.com/myx12345/p/9797838.html