題解「NOIP2017 逛公園」
阿新 • • 發佈:2020-11-30
有一個非常 \(\text{Naive}\) 的想法,由於 \(K\) 很小,我們可以設 \(f[x,i]\) 為從 \(x\) 出發到 \(n\) ,長度不超過 \(dis_x+i\) 的路徑條數,其中 \(dis_x\) 為 \(x\to n\) 的最短路長度。於是有轉移方程:
\[f[x,i]=\sum f[y,(k+dis_x)-(dis_y+w(x,y))] \]如果一個狀態被訪問超過 \(1\) 次,就說明存在 \(0\) 環,路徑條數無限,直接輸出 \(-1\) 即可。上述過程直接使用記憶化搜尋實現,時間複雜度為 \(O(nm)\)。
#include<cstdio> #include<queue> #include<cstdlib> #include<algorithm> #include<cstring> #include<vector> #include<functional> const int inf=0x3f3f3f3f; int n,m,K,mod; int cnt=0; std::vector<int> mp[100005],val[100005]; int h[100005],to[400005],ver[400005],w[400005]; int dis[100005],b[100005],vis[100005][55],f[100005][55]; struct edge {int x,y,w;}e[200005]; inline int read() { register int x=0,f=1;register char s=getchar(); while(s>'9'||s<'0') {if(s=='-') f=-1;s=getchar();} while(s>='0'&&s<='9') {x=x*10+s-'0';s=getchar();} return x*f; } inline void add(int x,int y,int z) {to[++cnt]=y;ver[cnt]=h[x];w[cnt]=z;h[x]=cnt;} inline void spfa() { std::queue<int> Q; for(register int i=1;i<=n;++i) b[i]=0,dis[i]=inf; dis[n]=0; Q.push(n); while(Q.size()) { int x=Q.front(); Q.pop(); b[x]=0; for(register int i=h[x];i;i=ver[i]) { int y=to[i]; if(dis[y]>dis[x]+w[i]) { dis[y]=dis[x]+w[i]; if(!b[y]) {b[y]=1; Q.push(y);} } } } } inline int dfs(int x,int k) { if(vis[x][k]) {throw -1;} if(f[x][k]!=-1) return f[x][k]; vis[x][k]=1; f[x][k]=(x==n); for(register int i=0;i<mp[x].size();++i) { int y=mp[x][i],w=val[x][i]; if(k+dis[x]-dis[y]-w>=0&&k+dis[x]-dis[y]-w<=K) f[x][k]=(f[x][k]+dfs(y,k+dis[x]-dis[y]-w))%mod; } vis[x][k]=0; return f[x][k]; } int main() { int T=read(); while(T--) { n=read(); m=read(); K=read(); mod=read(); cnt=0; for(register int i=1;i<=n;++i) h[i]=0; for(register int i=1;i<=n;++i) {mp[i].clear();val[i].clear();} for(register int i=1;i<=m;++i) { int x=read(),y=read(),w=read(); add(y,x,w); mp[x].push_back(y); val[x].push_back(w); } for(register int i=1;i<=n;++i) for(register int j=0;j<=K;++j) f[i][j]=-1,vis[i][j]=0; spfa(); try { int res=dfs(1,K); printf("%d\n",res); }catch(int x) { printf("-1\n"); } } return 0; }