Live2D

【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 
*/
posted @ 2019-10-25 19:46  tqr06  阅读(141)  评论(0编辑  收藏  举报