【NOIP2017】逛公园
作者:互联网
策策同学特别喜欢逛公园。公园可以看成一-张N个点M条边构成的有向图,且没有自环和重边
其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花的时间
策策每天都会去逛公园,他总是从1号点进去,从N号点出来
策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样
同时策策还是一一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间
如果1号点到N号点的最短路长为d ,那么策策只会喜欢长度不超过d + K的路线
策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?
为避免输出过大,答案对P取模。
如果有无穷多条合法的路线,请输出-1
先spfa跑出每个点的最短路径
然后记录到每个点时的剩余值(即还可以多走多少)
每次直接记忆化搜索即可
注意判断零环
#include<bits/stdc++.h>
#define ll long long
#define N 200005
using namespace std;
int T,n,m,k,p,u,v,w;
struct Edge
{
int next,to,dis;
}edge[N<<1],edge2[N<<1];
int cnt=0,head[N],cnt2=0,head2[N];
inline void add_edge(int from,int to,int dis)
{
edge[++cnt].next=head[from];
edge[cnt].to=to;
edge[cnt].dis=dis;
head[from]=cnt;
}
inline void add_edge2(int from,int to,int dis)
{
edge2[++cnt2].next=head2[from];
edge2[cnt2].to=to;
edge2[cnt2].dis=dis;
head2[from]=cnt2;
}
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
bool vis[N];
int dis[N];
queue<int> q;
void spfa(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;vis[s]=1;q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();vis[u]=0;
for(register int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis)
{
dis[v]=dis[u]+edge[i].dis;
if(!vis[v])
{
q.push(v);
vis[v]=1;
}
}
}
}
}
ll dp[N][55];
bool check[N][55];
ll dfs(int u,int rest)
{
ll res=0;
if(rest<0||rest>k) return 0;
if(check[u][rest])
{
check[u][rest]=0;
return -1;
}
if(dp[u][rest]!=-1) return dp[u][rest];//记忆化搜索
check[u][rest]=1;
for(register int i=head2[u];i;i=edge2[i].next)
{
int v=edge2[i].to;
ll use=dfs(v,dis[u]+rest-dis[v]-edge2[i].dis);
if(use==-1)
{
check[u][rest]=0;
return -1;
}
res=(res+use)%p;
}
check[u][rest]=0;
if(u==1&&rest==0) res++;
return dp[u][rest]=res;
}
inline void init()
{
cnt=cnt2=0;
memset(head,0,sizeof(head));
memset(head2,0,sizeof(head2));
memset(dp,-1,sizeof(dp));
memset(check,0,sizeof(check));
}
int main()
{
read(T);
while(T--)
{
init();
read(n);read(m);read(k);read(p);
for(register int i=1;i<=m;++i)
{
read(u);read(v);read(w);
add_edge(u,v,w);
add_edge2(v,u,w);
}
spfa(1);
ll ans=0;
for(register int i=0;i<=k;++i)
{
ll res=dfs(n,i);
if(res==-1) {printf("-1\n");goto ed;}
ans=(ans+res)%p;
}
printf("%lld\n",ans);
ed:;
}
return 0;
}
/*
1
5 7 10 10000000
1 5 2
1 2 10000
1 3 10000
3 4 0
4 2 0
2 3 0
3 5 10000
*/
标签:NOIP2017,int,res,rest,策策,逛公园,check,dis 来源: https://www.cnblogs.com/tqr06/p/11740368.html