原題傳送門
n oi
p2017tg
d1t3
noip2017tgd1t3
noip20
17tg
d1t3
當然是先跑個dij
kstr
adijkstra
dijkst
ra把最短路求出來
然後想到dp求答案
d pu
,d
dp_dp
u,d
表示到u
uu路程為d
dd方案數
狀態太多,看到k
<=50
k<=50
k<=5
0更改狀態dpu
,d
dp_dp
u,d
表示路程為dis
u+
ddis_u+d
disu+
d的方案數(dis
udis_u
disu
表示到u
uu的最短路)
然後用加法原理轉移
需要從最終態n
nn跑到最初態1
11所以跑反圖
直接拓撲上跑好像很麻煩,用記憶化dfs
dfsdf
s考慮一下-1的情況,就是0環的情況,開乙個fla
gu,d
flag_
flagu,
d的陣列,如果重複到這個狀態兩遍就說明有0環
code:
#include
#define maxn 200010
#define maxm 51
using
namespace std;
struct node};
priority_queue q;
struct edgeedge[maxn <<1]
, edge2[maxn <<1]
;int num, num2, head[maxn]
, head2[maxn]
, dis[maxn]
, vis[maxn]
, flag[maxn]
[maxm]
, dp[maxn]
[maxm]
, n, m, k, p;
inline
intread()
void
addedge
(int x,
int y,
int z)
, head[x]
= num;
}void
addedge2
(int x,
int y,
int z)
, head2[x]
= num2;
}void
dijkstra()
);while
(!q.
empty()
));}
}}}int
dfs(
int u,
int l)
if(u ==1&&
!l)++sum;
dp[u]
[l]= sum;
flag[u]
[l]=0;
return sum;
}int
main()
dijkstra()
;memset
(dp,
255,
sizeof
(dp));
memset
(flag,0,
sizeof
(flag));
int ans =
0, flag =0;
for(
int i =
0; i <= k;
++i)
(ans +
= tmp)
%= p;}if
(!flag)
printf
("%lld\n"
, ans)
;else
puts
("-1");
}return0;
}
洛谷3953 逛公園(DP)
原題 這道題目看到k特別小,而且k n的空間不會gg,那麼我們考慮乙個dp對吧。設 dp i k 表示到了點i與最短路相差k值的方案數,然後直接記搜 不想用拓撲序列 就可以了。luogu judger enable o2 include include include include include...
洛谷P3953 逛公園
題目 題解 f u k 表示 dis u,n mindis u,n k的方案數,答案就是 f 1 k f u k f v k mindis v,n mindis u,n w 這樣怎麼判 0環呢?只要在搜尋的時候記錄個 instack 就 ok 了 如果當前的 v還在搜尋的棧中就可以直接返回 1了 不...
洛谷P3953 逛公園
發現 k leq 50 猜想時間複雜度肯定與 k 有關。令 dis x 表示 1 到 x 的最短路。考慮 dp。先不考慮無限解得情況,設 f x i 表示到達點 x 走過的路程長度為 dis x i 的方案數。那麼 f x i 肯定由一條邊 y,x 轉移而來。設 y,x 的長度為 d 則這條路徑到 ...