洛谷 P3953 [NOIP2017 提高组] 逛公园(最短路,记忆化搜索)

Posted 尹昱钦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P3953 [NOIP2017 提高组] 逛公园(最短路,记忆化搜索)相关的知识,希望对你有一定的参考价值。

传送门


解题思路

\\(dp[i][j]\\) 表示从 \\(1\\) 号点到 \\(i\\) 号点的长度比最短路多 \\(j\\) 的路径的条数。
则答案为:

\\[ans=\\sum_{i=0}^{k}dp[n][i] \\]

\\(n\\) 开始在反图上进行转移,转移方程为:

\\[dp[u][k]=\\sum dp[v][k-(value-(dis[u]-dis[v]))] \\]

其中 \\(v\\)\\(u\\) 的子节点,\\(value\\) 为边权,\\(dis[i]\\)\\(1\\) 号点到 \\(i\\) 号点的最短路长度。
初始化:\\(dp[1][0]=1\\)
判断是否经过零环:若求解某个dp值时有用到了此dp值,则必有零环。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=100005;
int T,n,m,mod,k,dp[maxn][55],dis[maxn],p[maxn],P[maxn],cnt1,cnt2;
int on[maxn],in[maxn],vis[maxn][55],wrong;
struct node{
	int u,v,w,next;
}e[maxn*2],E[maxn*2];
void insert1(int u,int v,int w){
	cnt1++;
	e[cnt1].u=u;
	e[cnt1].v=v;
	e[cnt1].w=w;
	e[cnt1].next=p[u];
	p[u]=cnt1;
}
void insert2(int u,int v,int w){
	cnt2++;
	E[cnt2].u=u;
	E[cnt2].v=v;
	E[cnt2].w=w;
	E[cnt2].next=P[u];
	P[u]=cnt2;
}
void dfs1(int u){
	on[u]=1;
	for(int i=p[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(on[v]) continue;
		dfs1(v);
	}
}
void spfa(){
	memset(dis,0x3f,sizeof(dis));
	memset(in,0,sizeof(in));
	queue<int> q;
	in[1]=1;
	dis[1]=0;
	q.push(1);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		in[u]=0;
		for(int i=p[u];i!=-1;i=e[i].next){
			int v=e[i].v;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				if(!in[v]){
					q.push(v);
					in[v]=1;
				}
			}
		}
	}
}
int dfs(int u,int now){
	if(now<0) return 0;
	if(vis[u][now]){
		wrong=1;
		return dp[u][now]=0;
	}
	if(dp[u][now]!=-1) return dp[u][now];
	dp[u][now]=0;
	vis[u][now]=1;
	for(int i=P[u];i!=-1;i=E[i].next){
		int v=E[i].v;
		if(!on[v]) continue;
		dp[u][now]=(dp[u][now]+dfs(v,now-(E[i].w-(dis[u]-dis[v]))))%mod;
	}
	vis[u][now]=0;
	if(u==1&&now==0) dp[u][now]=1;
	return dp[u][now];
}
void work(){
	dfs1(1);
	spfa();
	int ans=0;
	wrong=0;
	for(int i=0;i<=k;i++){
		ans=(ans+dfs(n,i))%mod;
		if(wrong==1){
			printf("-1\\n");
			return;
		}
	}
	printf("%d\\n",ans);
}
int main(){
	cin>>T;
	while(T--){
		memset(on,0,sizeof(on));
		memset(p,-1,sizeof(p));
		memset(P,-1,sizeof(P));
		memset(dp,-1,sizeof(dp));
		cnt1=cnt2=0;
		cin>>n>>m>>k>>mod;
		for(int i=1;i<=m;i++){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			insert1(u,v,w);
			insert2(v,u,w);
		}
		work();
	}
    return 0;
}

//NOIP2017提高组Day1 t3

以上是关于洛谷 P3953 [NOIP2017 提高组] 逛公园(最短路,记忆化搜索)的主要内容,如果未能解决你的问题,请参考以下文章

P3953 NOIP2017 d1t3 逛公园

Luogu P3953NOIP2017逛公园最短路+拓扑排序+动态规划

模板LIS模板 洛谷P1091 [NOIP2004提高组]合唱队形 [2017年4月计划 动态规划11]

洛谷P1965 转圈游戏 [2013NOIP提高组 D1T1][2017年6月计划 数论04]

洛谷P1080 [NOIP2012提高组D1T2]国王游戏 [2017年5月计划 清北学堂51精英班Day1]

洛谷-拼数-NOIP1998提高组复赛