P3953 逛公园(dp,最短路)

P3953 逛公园

题目描述

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

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

策策喜欢新鲜的事物,它不希望有两天逛公园的路线完全一样,同时策策还是一个 特别热爱学习的好孩子,它不希望每天在逛公园这件事上花费太多的时间。如果1号点 到NN号点的最短路长为dd,那么策策只会喜欢长度不超过d + Kd+K的路线。

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

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

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

输入输出格式

输入格式:

 

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

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

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

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
2
5 7 2 10
1 2 1
2 4 0
4 5 2
2 3 2
3 4 1
3 5 2
1 5 3
2 2 0 10
1 2 0
2 1 0
输出样例#1: 复制
3
-1

说明

【样例解释1】

对于第一组数据,最短路为 33。 $1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5$ 为 33 条合法路径。

【测试数据与约定】

对于不同的测试点,我们约定各种参数的规模不会超过如下

测试点编号  TT   NN   MM   KK   是否有0边
1 5 5 10 0
2 5 1000 2000 0
3 5 1000 2000 50
4 5 1000 2000 50
5 5 1000 2000 50
6 5 1000 2000 50
7 5 100000 200000 0
8 3 100000 200000 50
9 3 100000 200000 50
10 3 100000 200000 50

对于 100%的数据, 1 \le P \le 10^9,1 \le a_i,b_i \le N ,0 \le c_i \le 10001P109,1ai,biN,0ci1000。

数据保证:至少存在一条合法的路线。

 

#include<bits/stdc++.h>

#define b 1000007
#define ll long long

using namespace std;
ll n,m,k,p,ans,cnt;
ll head[b],dis[b],C[b];
ll vis[b];
struct edge{
    ll u,v,net,w;
}e[b<<1];
queue<ll>q;

inline void add(int u,int v,int w)
{
    e[++cnt].v=v;e[cnt].w=w;e[cnt].net=head[u];head[u]=cnt;
}

inline ll read()
{
    ll x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void spfa(int u)
{
    dis[u]=0;vis[u]=1;C[u]=1;q.push(u);
    while(!q.empty())
    {
        int now=q.front();q.pop();
        vis[now]=0;
        for(int i=head[now];i;i=e[i].net)
        {
            int v=e[i].v;
            if(dis[v]>dis[now]+e[i].w)
            {
                dis[v]=dis[now]+e[i].w;
                C[v]=C[u];
                if(!vis[v]) vis[v]=1,q.push(v);
            }
            else if(dis[v]==dis[now]+e[i].w) 
            {
                if(!vis[v]) vis[v]=1,q.push(v);
                C[v]+=C[u];C[v]%=p;
            }
        }
    }
}

void clear()
{
    memset(C,0,sizeof C);
    memset(dis,127/3,sizeof dis);
    memset(vis,0,sizeof vis);
    memset(head,0,sizeof head);
    memset(e,0,sizeof e);
    while(!q.empty()) q.pop();
    cnt=0;
}

int main()
{
    int T;T=read();
    while(T--)
    {
        clear();
        n=read();m=read();k=read();p=read();
        int x,y,z;
        for(int i=1;i<=m;i++)
        {
            x=read();y=read();z=read();
            add(x,y,z);
        }
        spfa(1);C[n]%=p;
        cout<<C[n]<<endl;
    }
}
20暴力
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>

#define N 200007

using namespace std;
int T,b,n,m,k,mod,cnt,head[N];
int from[N],to[N],w[N];
int dis[N],vis[N],dp[N][51];
int in[N],re[N],flag;
struct edge{
    int next,to,w;
}e[N<<1];
queue<int>q;

inline int read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

void add(int x,int y,int w)
{
    e[++cnt]=(edge){head[x],y,w};
    head[x]=cnt;
}

int DFS(int x,int res)//返回到达x点还剩res步可以绕的方案数
{
    if(~dp[x][res]) return dp[x][res];
    dp[x][res]=(x==1);
    for(int i=head[x];i;i=e[i].next)
    {
        int R=e[i].to;
        int tt=res-((dis[R]+e[i].w)-dis[x]);//通过这条边多绕了一会
        if(tt<0) continue;
        if(in[R]&&re[R]==tt) flag=1;//如果说res一直没有减少的情况下搜出来一个圈,说明有0环
        else in[R]=1,re[R]=tt;
        (dp[x][res]+=DFS(R,tt))%=mod;
        in[R]=0;re[R]=0;
    }
    return dp[x][res];
}
void Work()
{
    memset(head,0,sizeof(head));cnt=0;
    b=read();m=read();k=read();mod=read();
    for(int i=1;i<=m;i++)
    {
        from[i]=read();to[i]=read();w[i]=read();
        add(from[i],to[i],w[i]);
    }
    
    memset(dis,63,sizeof(dis));
    q.push(1);dis[1]=0;vis[1]=1;
    while(!q.empty())
    {
        int x=q.front();
        for(int i=head[x];i;i=e[i].next)
        {
            int R=e[i].to;
            if(dis[R]<=dis[x]+e[i].w) continue;
            dis[R]=dis[x]+e[i].w;
            if(!vis[R]) vis[R]=1,q.push(R);
        }
        q.pop();vis[x]=0;
    }

    memset(head,0,sizeof(head));cnt=0;
    memset(dp,-1,sizeof(dp));flag=0;
    for(int i=1;i<=m;i++)
        add(to[i],from[i],w[i]);
    DFS(b,k);
    printf("%d\n",flag?-1:DFS(b,k));
}
int main()
{
    T=read();
    while(T--)Work();  
    return 0;
}

 

posted @ 2018-10-15 17:36  安月冷  阅读(202)  评论(0编辑  收藏  举报