逛公园

Posted oieredsion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逛公园相关的知识,希望对你有一定的参考价值。

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

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

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

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

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

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

解:
思路很好想
定义 f[i][j]表示以i号点为结尾的 距离起点距离为 dis+j j是偏量dis是最短距离 的方案数
画个图可以知道 f[i][j]=(sum) $f[u][j-(dis[u]+le[s]-dis[i])] $ 可以利用记忆化搜索
如果有0环则无解
注意到我们tarjan求的是强连通分量 不是强连通子图
所以我们可以建立边权为0的图求tarjan 求到的环一定满足充要条件
注意判断这个环是否满足条件

code:

//
#include<bits/stdc++.h>
using namespace std;
typedef  long long ll;
#define maxnn 100005
#define maxn 500005
ll f[maxnn][55];
#define inf 10000000
int T;
ll n,m,k,p;
int is[maxnn];
int ty=0;
int book[maxnn][55];
int dfn[maxnn],low[maxnn],vii,instack[maxnn];
int las[maxn],en[maxn],le[maxn],tot,nex[maxn];
int zlas[maxn],zen[maxn],zle[maxn],ztot,znex[maxn];
int las1[maxn],en1[maxn],le1[maxn],tot1,nex1[maxn];
ll dis[maxnn];
ll dis1[maxnn];
int mark[maxnn];
int ttt[maxnn];
int co[maxnn];
int sec;
int belong[maxnn];
int mask[maxnn];
stack<int > S;
void tarjan(int u) {
    int v;
    mask[u]=1;
    dfn[u]=low[u]=++vii;
    instack[u]=1;
    S.push(u);
    for(int i=zlas[u]; i; i=znex[i]) {
        int y=zen[i];
        if(!dfn[y]) {
            tarjan(y);
            low[u]=min(low[u],low[y]);
        } else if(dfn[y]&&instack[y]) {
            low[u]=min(low[u],dfn[y]);
        }
    }
    if(dfn[u]==low[u]) {
        sec++;
        do {
            v=S.top();
            S.pop();
            belong[v]=sec;
            if(dis[v]+dis1[v]<=dis[n]+k)
            {
                is[sec]=1;
            }
            ttt[sec]++;
            instack[v]=0;
        } while(v!=u);
    }
    if(ttt[sec]>=2&&is[sec])
    {
            ty=1;
    }
}
queue<int > Q;
void spfa() {
    for(int i=1; i<=n; i++) {
        mark[i]=0;
        dis[i]=inf;
    }
    dis[1]=0;
    Q.push(1);
    while(Q.size()) {
        int v=Q.front();
        mark[v]=0;
        Q.pop();
        for(int i=las1[v]; i; i=nex1[i]) {
            int u=en1[i];
            if(dis[u]>dis[v]+le1[i]) {
                dis[u]=dis[v]+le1[i];
                if(!mark[u]) {
                    Q.push(u);
                }
            }
        }
    }
}
void spfa1() {
    for(int i=1; i<=n; i++) {
        mark[i]=0;
        dis1[i]=inf;
    }
    dis1[n]=0;
    Q.push(n);
    while(Q.size()) {
        int v=Q.front();
        mark[v]=0;
        Q.pop();
        for(int i=las[v]; i; i=nex[i]) {
            int u=en[i];
            if(dis1[u]>dis1[v]+le[i]) {
                dis1[u]=dis1[v]+le[i];
                if(!mark[u]) {
                    Q.push(u);
                }
            }
        }
    }
}

void zadd(int a,int b,int c) {
    zen[++ztot]=b;
    znex[ztot]=zlas[a];
    zlas[a]=ztot;
    zle[ztot]=c;
}
void add1(int a,int b,int c) {
    en1[++tot1]=b;
    nex1[tot1]=las1[a];
    las1[a]=tot1;
    le1[tot1]=c;
}
void add(int a,int b,int c) {
    en[++tot]=b;
    nex[tot]=las[a];
    las[a]=tot;
    le[tot]=c;
}
ll dfs(int v,ll k) {
    if(~f[v][k]) return f[v][k];
    if(v==1)
    {
        if(k==0)
        return 1;
        
    } 
    ll ans=0;
    for(int i=las[v]; i; i=nex[i]) {
        int u=en[i];
        if(k-(dis[u]+1LL*le[i]-dis[v])>=0)
         ans=(ans+dfs(u,1LL*k-(dis[u]+1LL*le[i]-dis[v])))%p;
        }
    f[v][k]=ans%p;
    return f[v][k];
}
void clear()
{
    ty=0;
      memset(is,0,sizeof(is));
    while(S.size()) S.pop();
        memset(mark,0,sizeof(mark));
        memset(f,-1,sizeof(f));
        memset(book,0,sizeof(book));
        memset(las1,0,sizeof(las1));
        memset(zlas,0,sizeof(zlas));
        memset(las,0,sizeof(las));
        memset(en1,0,sizeof(en1));
        memset(zen,0,sizeof(zen));
        memset(en,0,sizeof(en));
        memset(nex1,0,sizeof(nex1));
        memset(nex,0,sizeof(nex));
        memset(znex,0,sizeof(znex));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(le,0,sizeof(le));
        memset(le1,0,sizeof(le1));
        memset(instack,0,sizeof(instack));
        memset(mask,0,sizeof(mask));
        memset(belong,0,sizeof(belong));
        memset(co,0,sizeof(co));
        memset(ttt,0,sizeof(ttt));
        ztot=0;
}
int main() {
    freopen("tes","r",stdin);
    freopen("anss","w",stdout);
    cin>>T;
    while(T--) {
       clear();
        sec=0;
        tot1=0;
        vii=0;
        tot=0;
        int a,b,c;
        cin>>n>>m>>k>>p;
        
        for(int i=1; i<=m; i++) {
            cin>>a>>b>>c;
            add1(a,b,c);
            add(b,a,c);
            if(c==0)
            {
                zadd(a,b,c);
            }
        }
     
        spfa();
        spfa1();
        ll ans=0; 
        for(int i=1; i<=n; i++)
         if(!mask[i]) tarjan(i); 
         
         if(ty)
         {
             puts("-1");
             continue;
         }
       for(int i=0;i<=k;i++)
        ans=(ans+dfs(n,i))%p;
            printf("%lld
",ans%p);
    }
}

以上是关于逛公园的主要内容,如果未能解决你的问题,请参考以下文章

Noip2017 逛公园

P3953 逛公园

[NOIP2017]逛公园

洛谷3953:逛公园——题解

Luogu P3953 逛公园(最短路+记忆化搜索)

TYVJ1427 小白逛公园