【逛公園】
阿新 • • 發佈:2019-01-01
我在有0環的圖裡跑了最短路計數
我可能已經是個廢物啦
很早之前就想寫這道題啦,但是太菜了發現自己不會,今天終於寫啦
首先我們建圖的時候建出一個正圖還有一個反圖,我們對著這兩個圖分別跑兩次最短路,求出\(1\)到所有點的最短路,以及所有點到\(n\)的最短路
如果不考慮無解的情況,我們現在就可以大力記搜了
我們設\(dp[x][j]\)表示從\(x\)走到\(n\)相比\(x\)到\(n\)的最短路多走了\(j\)的路徑條數
之後大力記搜即可,\(ans=\sum_{i=0}^Kdp[1][i]\)
我們去記憶化搜尋就行了,比如說從\(dp[i][now]\)轉移到\(j\)這個點,我們轉移的條件就是從\(i\)
之後邊界條件就是\(dp[n][0]=1\)
再來考慮一下如何判斷無解的情況
顯然如果有\(0\)環,而且環裡有一個點到\(1\)和\(n\)的最短路的和走的冤枉路小於\(K\),那麼就可以在這個環裡一直繞下去,就會出現無解了
顯然我們只需要考慮\(0\)
其實不不是非常難,主要就是\(dp\)的思想還有最簡單的圖論
但是我非常sb,我對於存在\(0\)環的圖跑了最短路計數,顯然這種圖的最短路條數是無限的,這樣跑出來顯然是錯的
程式碼
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define re register #define maxn 100005 #define LL long long #define mp std::make_pair int n,m,K,num[2],cnt; int mod; typedef std::pair<int,int> pii; std::priority_queue<pii,std::vector<pii>,std::greater<pii> > q; struct node { int v,nxt,w; }e[2][maxn<<1]; struct ZE { int v,nxt; }E[maxn<<1]; int Head[maxn]; inline void write(int x) { if(x>9) write(x/10); putchar(x%10+'0'); } inline void add(int x,int y) { E[++cnt].v=y; E[cnt].nxt=Head[x]; Head[x]=cnt; } int dp[maxn][51],Q[maxn],r[maxn]; int head[2][maxn],dis[2][maxn]; int f[maxn]; inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } inline void add_edge(int x,int y,int z,int opt) { e[opt][++num[opt]].v=y; e[opt][num[opt]].nxt=head[opt][x]; e[opt][num[opt]].w=z; head[opt][x]=num[opt]; } inline void dij(int s,int o) { memset(f,0,sizeof(f)); while(!q.empty()) q.pop(); dis[o][s]=0; if(o) dp[s][0]=1; q.push(mp(dis[o][s],s)); while(!q.empty()) { int k=q.top().second; q.pop(); if(f[k]) continue; f[k]=1; for(re int i=head[o][k];i;i=e[o][i].nxt) if(dis[o][e[o][i].v]>dis[o][k]+e[o][i].w) { dis[o][e[o][i].v]=dis[o][k]+e[o][i].w; q.push(mp(dis[o][e[o][i].v],e[o][i].v)); } } } int dfs(int x,int now) { if(dp[x][now]) return dp[x][now]%mod; for(re int i=head[0][x];i;i=e[0][i].nxt) if(dis[1][x]-dis[1][e[0][i].v]-e[0][i].w+now>=0) dp[x][now]=(dp[x][now]+dfs(e[0][i].v,dis[1][x]-dis[1][e[0][i].v]-e[0][i].w+now))%mod; return dp[x][now]%mod; } int main() { int T=read(); while(T--) { cnt=num[0]=num[1]=0; memset(Head,0,sizeof(Head)); memset(head,0,sizeof(head)); memset(dis,0x7f,sizeof(dis)); memset(dp,0,sizeof(dp)); memset(Q,0,sizeof(Q)); memset(r,0,sizeof(r)); n=read(),m=read(),K=read(),mod=read(); int x,y,z; for(re int i=1;i<=m;i++) { x=read(),y=read(),z=read(); if(!z) add(x,y),r[y]++; add_edge(x,y,z,0),add_edge(y,x,z,1); } dij(1,0),dij(n,1); int tot=0; for(re int i=1;i<=n;i++) if(!r[i]) Q[++tot]=i; for(re int i=1;i<=tot;i++) { int t=Q[i]; for(re int j=Head[t];j;j=E[j].nxt) { r[E[j].v]--; if(!r[E[j].v]) Q[++tot]=E[j].v; } } int flag=0; for(re int i=1;i<=n;i++) if(r[i]&&dis[0][i]+dis[1][i]<=dis[0][n]+K) { puts("-1"); flag=1; break; } if(flag) continue; int ans=0; for(re int i=0;i<=K;i++) ans=(ans+dfs(1,i))%mod; write(ans),putchar(10); } return 0; }