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

题目描述

策策同学特别喜欢逛公园。公园可以看成一张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 10001P109,1ai,biN,0ci1000。

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

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

在此衷心感谢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

猜你喜欢

转载自www.cnblogs.com/kylara/p/9748884.html