[NOIP 2017] 逛公園
阿新 • • 發佈:2018-07-24
i++ inf make pri edge can 最短 bits push
[題目鏈接]
http://uoj.ac/problem/331
[算法]
首先,我們預處理出每個點到第N個點的最短路,這等價於在反圖上求第N個點到其余點的最短路
然後,我們用f[u][k]表示從第u個點到第n個點,至多走長度為dist(u,n) + k的路徑有多少種走法
記憶化搜索即可,註意判斷是否存在0環
[代碼]
#include<bits/stdc++.h> using namespace std; #define MAXN 100010 #define MAXM 200010 #define MAXK 55 constint INF = 2e9; int i,j,tot,ans,u,v,w,T,N,M,K,P; int head[MAXN],rhead[MAXN],dist[MAXN]; int f[MAXN][MAXK]; bool visited[MAXN][MAXK]; bool flag; struct Edge { int to,w,nxt; } e[MAXM << 1]; inline void addedge(int u,int v,int w) { tot++; e[tot] = (Edge){v,w,head[u]}; head[u]= tot; tot++; e[tot] = (Edge){u,w,rhead[v]}; rhead[v] = tot; } inline void dijkstra(int s) { int i,v,w,cur; priority_queue< pair<int,int> > q; static bool visited[MAXN]; while (!q.empty()) q.pop(); for (i = 1; i <= N; i++) { dist[i]= INF; visited[i] = false; } dist[s] = 0; q.push(make_pair(0,s)); while (!q.empty()) { cur = q.top().second; q.pop(); if (visited[cur]) continue; visited[cur] = true; for (i = rhead[cur]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; if (dist[cur] + w < dist[v]) { dist[v] = dist[cur] + w; q.push(make_pair(-dist[v],v)); } } } } inline int dp(int now,int k) { int i,v,w,tmp,cnt,ret; if (f[now][k] != -1) return f[now][k]; if (now == N) ret = 1; else ret = 0; if (visited[now][k]) return -1; visited[now][k] = true; for (i = head[now]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; tmp = k - (dist[v] + w - dist[now]); if (tmp < 0) continue; cnt = dp(v,tmp); if (cnt == -1) { flag = true; return -1; } else ret = (ret + cnt) % P; } visited[now][k] = false; return f[now][k] = ret; } int main() { scanf("%d",&T); while (T--) { scanf("%d%d%d%d",&N,&M,&K,&P); tot = 0; for (i = 1; i <= N; i++) head[i] = rhead[i] = 0; for (i = 1; i <= M; i++) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); } dijkstra(N); flag = false; for (i = 1; i <= N; i++) { for (j = 0; j <= K; j++) { f[i][j] = -1; visited[i][j] = false; } } ans = dp(1,K); if (flag) printf("-1\n"); else printf("%d\n",ans); } return 0; }
[NOIP 2017] 逛公園