NOIP2017 逛公园

题目描述

策策同学特别喜欢逛公园。公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边。其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花的时间。

策策每天都会去逛公园,他总是从1号点进去,从N号点出来。

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到N

号点的最短路长为d,那么策策只会喜欢长度不超过d+K的路线。

策策同学想知道总共有多少条满足条件的路线,你能帮帮它吗?

为避免输出过大,答案对P取模。

如果有无穷多条合法的路线,请输出1。

输入输出格式

输入格式:

第一行包含一个整数 T, 代表数据组数。

接下来T组数据,对于每组数据: 第一行包含四个整数 N,M,K,P,每两个整数之间用一个空格隔开。

接下来M行,每行三个整数ai,bi,ci,代表编号为ai,bi的点之间有一条权值为 ci的有向边,每两个整数之间用一个空格隔开。

输出格式:

输出文件包含 T 行,每行一个整数代表答案。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

首先反向边跑dij求每个点到终点最短路,然后记忆化搜索转移。

注意最后跑一遍搜-1 。

代码:

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
#define M 200050
inline int rd()
{
    int f = 1,c =  0;char ch = getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=(c<<1)+(c<<3)+ch-'0';ch=getchar();}
    return f*c;
}
int T,n,m,K,P,hed[N],cnt,ihed[N],icnt;
struct EG
{
    int to,w,nxt;
}ie[M],e[M];
void ae(int f,int t,int v)
{
    e[++cnt].to = t;
    e[cnt].w = v;
    e[cnt].nxt = hed[f];
    hed[f] = cnt;
}
void aie(int f,int t,int v)
{
    ie[++icnt].to = t;
    ie[icnt].w = v;
    ie[icnt].nxt = ihed[f];
    ihed[f] = icnt;
}
int dis[N];
bool vis[N];
struct node
{
    int x,d;
    node(){}
    node(int x,int d):x(x),d(d){}
    friend bool operator < (node a,node b)
    {
        return a.d>b.d;
    }
}tp;
bool ot;
/*void ck(int u)
{
    if(vis[u])
    {
        ot=1;
        return ;
    }
    vis[u]=1;
    for(int j=ihed[u];j;j=ie[j].nxt)
    {
        int to = ie[j].to;
        if(dis[to]>=dis[u]+ie[j].w)
        {
            dis[to]=dis[u]+ie[j].w;
            ck(to);
            if(ot)return ;
        }
    }
    vis[u]=0;
}*/
priority_queue<node>q;
void dij()
{
    memset(dis,0x3f,sizeof(dis));
    dis[n]=0;
    q.push(node(n,0));
    while(!q.empty())
    {
        tp = q.top();
        q.pop();
        int u = tp.x;
        if(vis[u])continue;
        vis[u]=1;
        for(int j=ihed[u];j;j=ie[j].nxt)
        {
            int to = ie[j].to;
            if(dis[to]>dis[u]+ie[j].w)
            {
                dis[to]=dis[u]+ie[j].w;
                q.push(node(to,dis[to]));
            }
        }
    }
}
int dp[N][55];
bool vs[N][55];
int dfs(int u,int k)
{
    if(dp[u][k]!=-1)return dp[u][k];
    vs[u][k]=1;
    dp[u][k] = 0;
    for(int to,tmp,j=hed[u];j;j=e[j].nxt)
    {
        to = e[j].to;
        tmp = k-dis[to]+dis[u]-e[j].w;
        if(tmp<0)continue;
        if(vs[to][tmp])ot=1;
        (dp[u][k]+=dfs(to,tmp))%=P;
    }
    vs[u][k]=0;
    return dp[u][k];
}
void init()
{
    memset(hed,0,sizeof(hed));
    memset(ihed,0,sizeof(ihed));
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    memset(dp,-1,sizeof(dp));
    cnt=icnt=0;
    ot=0;
}
int main()
{
    T=rd();
    while(T--)
    {
        init();
        n=rd(),m=rd(),K=rd(),P=rd();
        for(int u,v,w,i=1;i<=m;i++)
        {
            u=rd(),v=rd(),w=rd();
            ae(u,v,w);
            aie(v,u,w);
        }
        dis[n]=1;
//        ck(n);
//        if(ot)
//        {
//            printf("-1
");
//            continue;
//        }
        dij();
        dp[n][0]=1;
        int ans = 0;
        for(int k=0;k<=K&&ot==0;k++)
        {
            (ans+=dfs(1,k))%=P;
        }
        dfs(1,K+1);
        if(ot)printf("-1
");
        else printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9743643.html