其他分享
首页 > 其他分享> > 【NOIP2017】逛公园

【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