zoukankan      html  css  js  c++  java
  • 【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
    ");goto ed;}
    			ans=(ans+res)%p;
    		}
    		printf("%lld
    ",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 
    */
    
  • 相关阅读:
    Dom修改元素样式
    URL百分号编码
    accesskey附上一些实例
    dom实例
    dom 创建时间
    关系运算符
    赋值运算符
    js图片随机切换
    js自增图片切换
    transform-origin盒子旋转位置
  • 原文地址:https://www.cnblogs.com/tqr06/p/11740368.html
Copyright © 2011-2022 走看看