日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【NOIP2017】逛公园【最短路DAG】【dp】【拓扑排序】

發布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【NOIP2017】逛公园【最短路DAG】【dp】【拓扑排序】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意:給一張帯權有向圖,求 111nnn 長度不超過最短路長度 +k+k+k 的路徑條數 模 PPP。有無數條輸出 ?1-1?1 。

n≤105,m≤2×105,k≤50n\leq 10^5,m\leq 2\times 10^5,k\leq 50n105,m2×105,k50,邊權非負

先往最短路圖想

發現 kkk 很小,考慮硬上 dp。

f(u,k)f(u,k)f(u,k) 表示從 uuunnn 多走 kkk 的路徑數。

轉移枚舉下一步往哪里走。

f(u,k)=∑(u,v)∈Ef(v,k?(w(u,v)+disu?disv))f(u,k)=\sum_{(u,v)\in E}f(v,k-(w(u,v)+dis_u-dis_v))f(u,k)=(u,v)E?f(v,k?(w(u,v)+disu??disv?))

其中 disudis_udisu?111uuu 最短路長度。

在沒有零邊的基礎上,右邊這塊 w(u,v)+disu?disvw(u,v)+dis_u-dis_vw(u,v)+disu??disv?000 當且僅當 (u,v)(u,v)(u,v) 在最短路圖上。因為這是個 DAG,所以在最短路圖上跑拓撲排序,然后枚舉 kkk 更新就可以了。這樣可以拿到 707070 分的好成績。

有零邊時可能會出現 disn+kdis_n+kdisn?+k 內可達的零環,這樣答案為無窮大。如果拓撲排序后點 iii 入度不為 000 說明在零環上,此時如果 disi+disi′≤disn+kdis_i+dis'_i \leq dis_n+kdisi?+disi?disn?+k 就輸出 ?1-1?1。(dis′dis'dis 為到 nnn 的最短距離)

否則的話反正都走不到這里,直接把偽的拓撲序繼續往后做。

復雜度 O(nlog?n+nk)O(n\log n+nk)O(nlogn+nk)

#include <iostream> #include <cstdio> #include <cstring> #include <cctype> #include <algorithm> #include <utility> #include <queue> #define MAXN 100005 #define MAXM 200005 using namespace std; int n,m,k,P; inline int add(const int& x,const int& y){return x+y>=P? x+y-P:x+y;} inline int read() {int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans; } struct edge{int u,v,w;}e[MAXM]; int head[MAXN],nxt[MAXM],cnt; inline void addnode(int u,int v,int w) {e[++cnt]=(edge){u,v,w};nxt[cnt]=head[u];head[u]=cnt; } template<typename T,typename cmp=less<T> > struct heap {T val[MAXM];T* end;heap(){end=val;}inline bool empty(){return end==val;}inline void push(const T& v){*(end++)=v;push_heap(val,end,cmp());}inline T pop(){pop_heap(val,end,cmp());return *(--end);} }; typedef pair<int,int> pi; heap<pi,greater<pi> > q; int dis[MAXN],disn[MAXN],deg[MAXN]; inline void dij(int* dis,int s=1) {memset(dis,0x3f,sizeof(disn));dis[s]=0;q.push(make_pair(0,s));while (!q.empty()){int u=q.pop().second;for (int i=head[u];i;i=nxt[i])if (dis[u]+e[i].w<dis[e[i].v])dis[e[i].v]=dis[u]+e[i].w,q.push(make_pair(dis[e[i].v],e[i].v));} } int lis[MAXN],vis[MAXN],tim; void dfs(int u) {vis[u]=1;for (int i=head[u];i;i=nxt[i])if (dis[u]+e[i].w==dis[e[i].v]){++deg[e[i].v];if (!vis[e[i].v]) dfs(e[i].v);} } inline void topsort() {queue<int> q;tim=0;q.push(1);while (!q.empty()){int u=q.front();q.pop();lis[++tim]=u;for (int i=head[u];i;i=nxt[i])if (dis[u]+e[i].w==dis[e[i].v]&&(--deg[e[i].v]==0))q.push(e[i].v);} } int f[55][MAXN],u[MAXM],v[MAXM],w[MAXM]; int main() {for (int T=read();T;T--){cnt=tim=0;memset(head,0,sizeof(head));memset(nxt,0,sizeof(nxt));memset(deg,0,sizeof(deg));memset(vis,0,sizeof(vis));n=read(),m=read(),k=read(),P=read();for (int i=1;i<=m;i++) u[i]=read(),v[i]=read(),w[i]=read(),addnode(v[i],u[i],w[i]);dij(disn,n);cnt=0;memset(head,0,sizeof(head));memset(nxt,0,sizeof(nxt)); for (int i=1;i<=m;i++) addnode(u[i],v[i],w[i]);dij(dis);dfs(1);topsort();int ans=0;for (int i=1;i<=n;i++) if (deg[i]&&dis[i]+disn[i]<=dis[n]+k) {puts("-1");goto end;}memset(f,0,sizeof(f));f[0][n]=1;for (int t=0;t<=k;t++)for (int x=tim;x>=1;x--){int u=lis[x];for (int i=head[u];i;i=nxt[i]){int del=e[i].w-dis[e[i].v]+dis[u];if (t>=del) f[t][u]=add(f[t][u],f[t-del][e[i].v]);}}for (int i=0;i<=k;i++) ans=add(ans,f[i][1]);printf("%d\n",ans);end:;}return 0; }

總結

以上是生活随笔為你收集整理的【NOIP2017】逛公园【最短路DAG】【dp】【拓扑排序】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。