zoukankan      html  css  js  c++  java
  • [Noip2017]逛公园

    其实真的是一道思博题啊。为啥考试我就没想出来??

    因为长得太拓扑了(其他正解好像也确实是拓扑),然后顾忌到环就没想。太菜了还是。

    后来上课闲的没事一想,靠,记忆化搜索啊。这样一定是所有父亲都计算完不重不漏。

    (正着想不也是嘛)

    很难受,要不然能多点分。


    【问题描述】

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

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

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

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

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

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

    【输入格式】

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

    接下来$T$组数据,对于每组数据:

    第一行包含四个整数 $N,M,K,P$, 每两个整数之间用一个空格隔开。

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

    【输出格式】

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

    对于第一组数据,最短路为 3。

    1 – 5, 1 – 2 – 4 – 5, 1 – 2 – 3 – 5 为 3 条合法路径。


    用$dp[u][k]$表示从$1$到$u$点的所有路径里,比最短路多$k$的路径数。

    则有

    $dp[u][k]=sum dp[v][dis[u]+k-w-dis[v]]$

    $dis[x]$是从$1$到$x$的最短路。spfa预处理复杂度$O(n imes ??? )$。

    $w$是边权。$v$是所有有指向$u$的边的点。

    记忆化搜索即可。判0环的话,还没有写出完美的写法,如果有不包含$1$的0环,那么一个未确定的$dp$值被访问两次说明存在。

    复杂度$O(nk)$。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    using namespace std;
    const int N=100010;
    const int inf=0x3f3f3f3f;
    typedef long long ll;
    inline int read(){
        int r=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){r=r*10+c-'0';c=getchar();}
        return r*f;
    }
    struct Edge{
        int to,nxt,w;
    }e[N*2],E[N*2];
    int head[N],Head[N],cnt=1;
    void add(int u,int v,int w){
        e[cnt]=(Edge){v,head[u],w};
        head[u]=cnt;
        E[cnt]=(Edge){u,Head[v],w};
        Head[v]=cnt++;
    }
    int n,m,K,P;
    bool inq[N];
    int dis[N],f[N][51],c[N][51];
    void spfa(){
        deque<int>q;
        memset(dis,63,sizeof dis);
        dis[1]=0;q.push_back(1);inq[1]=1;
        while(!q.empty()){
            int u=q.front();q.pop_front();inq[u]=0;
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].to,w=e[i].w;
                if(dis[v]>dis[u]+w){
                    dis[v]=dis[u]+w;
                    if(!inq[v]){
                        if(!q.empty()&&dis[v]<=dis[q.front()])
                        q.push_front(v);
                        else q.push_back(v);
                    }
                }
            }
        }
    }bool ff=0;
    void Clear(){
        n=m=K=P=0;
        memset(inq,0,sizeof inq);
        memset(f,-1,sizeof f);
        memset(head,0,sizeof head);
        memset(Head,0,sizeof Head);
        memset(c,0,sizeof c);
        memset(e,0,sizeof e);
        memset(E,0,sizeof E);cnt=1;
        ff=0;
    }
    void Init(){
        n=read(),m=read(),K=read(),P=read();
        while(m--){
            int u=read(),v=read(),w=read();
            add(u,v,w);
        }
    }
     
    int dfs(int u,int k){
        if(~f[u][k])return f[u][k];
        c[u][k]=1;
        f[u][k]=0;
        for(int i=Head[u];i;i=E[i].nxt){
            int v=E[i].to,w=E[i].w;
            int t=dis[u]+k-w-dis[v];
            if(t<0)continue;
            if(c[v][t])ff=1;
            f[u][k]+=dfs(v,t),f[u][k]%=P;
        }
        c[u][k]=0;
        return f[u][k];
    }
    void Solve(){
        spfa();
        f[1][0]=1;
        int ans=0;
        for(int j=0;j<=K;j++)
        ans+=dfs(n,j),ans%=P;
        dfs(n,K+1);
        if(ff){
            cout<<-1<<endl;
            return ;
        }
        printf("%d
    ",ans);
    }
    int main(){
        int T=read();
        while(T--){
            Clear();
            Init();
            Solve();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    sql学习之1-create、select
    mysql利用binlog日志恢复数据库小实验
    vmware 存储路径
    ubuntu基本命令
    Java编程规范整理
    种菜之旅
    modSecurity规则学习(五)——DDOS攻击检测
    modSecurity规则学习(三)——SecRule
    modSecurity规则学习(二)——配置文件
    modSecurity规则学习(一)——配置文件
  • 原文地址:https://www.cnblogs.com/orzzz/p/7857847.html
Copyright © 2011-2022 走看看