【NOIP2017提高组 day1】逛公园

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41709770/article/details/82828745

题目

在这里插入图片描述
在这里插入图片描述


题解

– 首先要在图上跑一遍最短路是肯定的(spfa或迪杰斯特拉)
接着就是怎么算答案了
我们可以先建一个反图(方便从终点跑回起点)
设f[i][j]:从起点跑到i号节点时,与目前的最短路相差j的长度时的方案数
所以说我们怎么从f[i][j]转移到f[a][b]呢(i,a由一条长为w的路径相连)
可以推出:j-b=d[a]+w-d[i]
即:b=j+d[i]-d[a]-w
因为直接递推不能做
然后我们可以用记搜
从终点往回搜,边界状态是f[1][0]=1
用isv[i][j]判断这种情况是否出现过(判断0环)
还要特判一下1在0环内的情况(因为记搜无法判断这种情况)
小技巧:f初始值记为-1,判断是否遍历过用~可以快很多很多很多很多


代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int MAXN=100005;
const int MAXM=200005;

int t;
int n,m,k,p;
int head[MAXN],next[MAXM],to[MAXM],w[MAXM],cnt;
int Head[MAXN],Next[MAXM],To[MAXM],W[MAXM],Cnt;
queue<int>q;
int d[MAXN];
bool isv[MAXN];
long long f[MAXN][55];
bool Isv[MAXN][55],flag;
long long ans;

void R(int &n){
	char c;for(n=0;(c=getchar())<'0'||c>'9';);
	for(;c>='0'&&c<='9';c=getchar())n=n*10+c-48;
}

void add(int u,int v,int l){
	cnt++;
	next[cnt]=head[u];
	to[cnt]=v;
	w[cnt]=l;
	head[u]=cnt;
}

void add1(int u,int v,int l){
	Cnt++;
	Next[Cnt]=Head[u];
	To[Cnt]=v;
	W[Cnt]=l;
	Head[u]=Cnt;
}

void spfa(){
	memset(d,0x7f,sizeof(d));
	memset(isv,0,sizeof(isv));
	q.push(1);
	d[1]=0;
	isv[1]=1;
	while(q.size()){
		int x=q.front();
		q.pop();
		isv[x]=0;
		for(int i=head[x];i;i=next[i]){
			int y=to[i];
			if(d[x]+w[i]<d[y]){
				d[y]=d[x]+w[i];
				if(!isv[y]){
					isv[y]=1;
					q.push(y);
				}
			}
		}
	}
}

void eeeeee(){
	vector<int>Q;
	Q.push_back(1);
	for(int h=0;h<Q.size();h++){
		int x=Q[h];
		for(int i=head[x];i;i=next[i]){
			int y=to[i];
			if(y==1)
				flag=1;
			if(flag)
				return ;
			if(!w[i])
				Q.push_back(y);
		}
	}
}

int dfs(int x,int k){
	if(~f[x][k])
		return f[x][k];
	f[x][k]=0;
	for(int i=Head[x];i;i=Next[i]){
		int y=To[i];
		int j=d[x]-d[y]+k-W[i];
		if(j<0)
			continue;
		if(Isv[y][j])
			flag=1;
		else{
			Isv[y][j]=1;
			f[x][k]=(f[x][k]+dfs(y,j))%p;
			Isv[y][j]=0;
		}
		if(flag)
			return 0;
	}
	return f[x][k];
}

int main(){
	R(t);
	while(t--){
		R(n);
		R(m);
		R(k);
		R(p);
		cnt=0;
		memset(head,0,sizeof(head));
		Cnt=0;
		memset(Head,0,sizeof(Head));
		for(int i=1;i<=m;i++){
			int u,v,l;
			R(u);
			R(v);
			R(l);
			add(u,v,l);
			add1(v,u,l);
		}
		spfa();
		flag=0;
		memset(f,-1,sizeof(f));
		f[1][0]=1;
		memset(Isv,0,sizeof(Isv));
		ans=0;
		eeeeee();
		for(int i=0;i<=k;i++){
			if(flag)
				break;
			ans=(ans+dfs(n,i))%p;
		}
		if(flag)
			printf("-1\n");
		else
			printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41709770/article/details/82828745