給定乙個有向圖,起點為\(1\),終點為\(n\),求和最短路相差不超過\(k\)的路徑數量.有\(0\)邊.如果有無數條,則輸出\(-1\).
\(n\leq 10^5,k\leq 50\)
首先,有無數條邊的情況一定是在與最短路相差不超過\(k\)的一條路上有\(0\)環.
先不考慮\(0\)邊和\(0\)環,\(get\ 70pts\)做法:先跑乙個最短路,\(dis[i]\)表示從\(1\)到\(i\)的最短路徑.記\(f[u][k]\)表示從\(1\)到\(u\)路徑長度不超過\(dis[u]+k\)的路徑條數,\(f[u][k]\)顯然是轉移到\(f[v][dis[u]+k+w(u,v)-dis[v]]\).轉移順序顯然是從\(dis\)小的轉移到\(dis\)大的,直接按\(dis\)從小到大的順序.於是乙個\(o(nk)\)的\(dp\)就出爐了.
考慮正解.
首先看怎麼判斷無窮解.記\(f_i\)為\(1\)到\(i\)的最短路,\(g_i\)為\(i\)到\(n\)的最短路.判斷無窮解:先把所有可行的\(0\)邊拎出來,再看它們是不是組成了環.一條邊\((i,j)\)可行當且僅當\(f_i+g_j+w\leq f_n+k\).於是這裡就可以簡單判斷了.
接下來仍然是\(dp\),但是因為\(0\)邊的存在所以並不能直接按\(dis\)從小到大的順序轉移,我們需要另外一種方法來確定\(0\)邊兩個端點的轉移順序.考慮把所有可行的\(0\)邊的兩個端點拎出來,然後拓撲排序.最後對於所有的點,只需要按照\(f\)為第一關鍵字,拓撲排序排出來的順序為第二關鍵字排序,按照這個順序更新即可.
其實還有更加簡單的記憶化搜尋的寫法:
\(dfs(u,res)\)表示已經從\(1\)號結點跑到\(u\)結點,還有可以比最短路多走\(res\)的長度,走到\(n\)結點的方案數.顯然這裡需要跑乙個反向最短路\(dis\).答案是\(\sum dfs(v,res-(dis_v+w-dis_u))\).記憶化一下即可.
怎麼判斷\(0\)環呢?只需要記乙個\(stk_\)表示在搜尋樹中當前結點的祖先結點們有沒有出現過這個狀態,如果有,那麼就一定有\(0\)環.
我永遠喜歡記搜!
對了,還看到乙個非常神仙的分層圖求法.在這裡.
#include#define il inline
#define ri register int
#define go(i,a,b) for(ri i=a;i<=b;++i)
#define yes(i,a,b) for(ri i=a;i>=b;--i)
#define e(i,u) for(ri i=b[u];i;i=a[i].nt)
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define db double
#define inf 2147480000
#define pr pair#define mp make_pair
#define fi first
#define sc second
using namespace std;
il int read()
while(c>='0'&&c<='9')
return x*y;
}const int n=1e5+5;
int n,m,k,p,b[n],ct,dis[n],as,rem[n][55];
bool fl,stk[n][55];
priority_queueq;
struct nda[n*2];
struct ede[n*2];
il void add(ri u,ri v,ri w);b[u]=ct;}
il void inc(ri &x,ri y)
il void dijkstra()
stk[u][res]=0;return rem[u][res]=ret;
}int main()
; mem(b,0);ct=0;
go(i,1,m)add(e[i].v,e[i].u,e[i].w);
dijkstra();
mem(b,0);ct=0;
go(i,1,m)add(e[i].u,e[i].v,e[i].w);
mem(stk,0);mem(rem,0);rem[n][0]=1;
go(i,0,k)
if(fl)printf("-1\n");
else printf("%d\n",as);
}return 0;
}
NOIP 2017 逛公園 最短路 dp
題意 求出 從 1 到 n 的路徑長度小於等於最短路 k 的路徑個數 分析 首先觀察資料特點 30 的資料 k 0 且沒有 0 邊,等同於最短路計數 70 的資料沒有 0 邊,那麼就是相當於沒有 0 環 100 的資料 k le 50 首先考慮第一檔 顯然就是乙個最短路徑計數,是乙個非常經典的問題,...
比賽 NOIP2017 逛公園
考試的時候靈光一閃,瞬間推出dp方程,但是不知道怎麼判 1,然後?然後就炸了。後來發現,我只要把拓撲和dp分開,中間加乙個判斷,就ac了,可惜。看這道題,我們首先來想有哪些情況是 1 只要有零環在滿足題目要求的路徑上,那麼這條路徑就可以不停地走,於是就 1了。如何判有沒有零環呢?機械化地兩遍不同方向...
NOIP2017 洛谷 逛公園
初見安 這個本狸咕了4個月的題終於寫出來了qaq!這裡是傳送門 洛谷p3953 逛公園 策策每天都會去逛公園,他總是從1號點進去,從nn號點出來。策策喜歡新鮮的事物,它不希望有兩天逛公園的路線完全一樣,同時策策還是乙個 特別熱愛學習的好孩子,它不希望每天在逛公園這件事上花費太多的時間。如果1號點 到...