1. 程式人生 > >2018.11.07【NOIP2017】【洛谷P3953】逛公園(DP)(魔改最短路計數)

2018.11.07【NOIP2017】【洛谷P3953】逛公園(DP)(魔改最短路計數)

傳送門


解析:

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

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

因為我的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; }