2018.11.07【NOIP2017】【洛谷P3953】逛公园(DP)(魔改最短路计数)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/83833908

传送门


解析:

首先这鬼畜的最短路肯定你是要自己跑一遍的。

但是我是在反图上面跑。。

因为我的DP策略表示在当前点 u u 剩余冤枉路可以走 r e s t rest 走到终点的方案数,所以我需要的是每个点到终点的最短路,起点…不重要。

然后就直接这样子记忆化搜索一下就行了。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
    re int num;
    re char c;
    while(!isdigit(c=gc()));num=c^48;
    while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
    return num;
}

cs int N=100005,M=200005;
int last[N],nxt[M],to[M],ecnt;
int w[M];
inline void addedge(int u,int v,int val){
    nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
}

int dist[N];
namespace REV_GRAPH{
    int last[N],nxt[M],to[M],ecnt;
    int w[M];
    inline void addedge(int u,int v,int val){
        nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v,w[ecnt]=val;
    }
    set<pair<int,int> > q;
    inline void Dij(int S){
        memset(dist,0x3f,sizeof dist);
        dist[S]=0;
        q.insert(make_pair(0,S));
        while(!q.empty()){
            int u=q.begin()->second;
            q.erase(q.begin());
            for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
                if(dist[v]>dist[u]+w[e]){
                    q.erase(make_pair(dist[v],v));
                    dist[v]=dist[u]+w[e];
                    q.insert(make_pair(dist[v],v));
                }
            } 
        } 
    }
    inline void clear(){
        memset(last,0,sizeof last);ecnt=0;
    }
}

int f[N][52];
bool vis[N][52];
bool flag;

inline void clear(){
    memset(last,0,sizeof last);ecnt=0;
    memset(f,-1,sizeof f);
    memset(vis,0,sizeof vis);
    REV_GRAPH::clear();
    flag=true;
}

int n,m,k,mod;

inline int dfs(int u,int rest){
    if(vis[u][rest]){
        flag=false;
        return 0;
    }
    if(~f[u][rest])return f[u][rest];
    vis[u][rest]=true;
    int res=0;
    for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
        int tmp=rest-(dist[v]+w[e]-dist[u]);
        if(tmp<0)continue;
        res=(res+dfs(v,tmp))%mod;
        if(!flag)return 0;
    }
    if(n==u&&rest==0)res=1;
    vis[u][rest]=false;
    return f[u][rest]=res;
}


int T;
signed main(){
    T=getint();
    while(T--){
        n=getint();m=getint();k=getint();mod=getint();
        clear();
        for(int re i=1;i<=m;++i){
            int u=getint(),v=getint(),val=getint();
            addedge(u,v,val);
            REV_GRAPH::addedge(v,u,val);
        }
        REV_GRAPH::Dij(n);
        int ans=0;
        for(int re i=0;i<=k;++i){
            ans=(ans+dfs(1,i))%mod;
            if(!flag)break;
        }
        printf("%d\n",flag?ans:-1);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/83833908