考慮到邊權可能為
0 ,轉移的順序會影響最後的結果,因此我們用記憶化搜尋代替直接dp
0 環
如何判斷乙個點
u是否在滿足條件的路徑上?顯然我們可以知道這個點滿足di
s1[u
]+di
sn[u
]≤di
s1[n
]+k 我們把所有長度為
0 的邊建成乙個新圖,然後用ta
rjan
找出所有點數大於
1 的強連通分量(也就是
0環),逐個檢查上面的點即可
時間複雜度o(
mk)
#include
#include
#include
#include
#include
using
namespace
std;
inline
int get()
const
int maxn = 0x3f3f3f3f;
const
int n = 1e5 + 5, m = n << 1;
int d1[n], dn[n], h[m], f[n][55], a[n];
int tm, n, m, k, p, ans, top, tis;
int dfn[n], low[n], stk[n];
bool vis[n], inv[n], flag;
struct edge
;edge p[m], *t = p, *lst[n];
edge q[m], *q = q, *rst[n];
inline
void linkedge(int x, int y, int z)
inline
void rinkedge(int x, int y, int z)
inline
void spfa(int src, int *dis)}}
}inline
void add(int &x, int y)
inline
int dfs(int x, int d)
return f[x][d];
}inline
void ckmin(int &x, int y)
inline
void tarjan(int x)
if (dfn[x] == low[x])
}int main()
spfa(1, d1); spfa(n, dn);
memset(dfn, 0, sizeof(dfn));
memset(inv, false, sizeof(inv)); flag = false;
for (int i = 1; i <= n; ++i)
if (!dfn[i]) tarjan(i);
if (flag)
for (int i = 1; i <= n; ++i)
for (edge *e = lst[i]; e; e = e->nxt)
e->cst += d1[i] - d1[e->to];
for (int k = 0; k <= k; ++k)
for (int i = 1; i <= n; ++i)
f[i][k] = -1;
ans = 0;
for (int k = 0; k <= k; ++k)
add(ans, dfs(1, k));
printf("%d\n", ans);
}// fclose(stdin); fclose(stdout);
return
0;}
洛谷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 則這條路徑到 ...
洛谷P3960 NOIP2017 列隊
資料結構題還是挺好玩的 注意到每次只變動三個點 x,y x,m n,m 其他地方都是整塊移動。可以開n 1個線段樹,前n個存每行前m 1個人,最後乙個存第m列的人。x,y 位置的人出列時,抽出該位置的標號,加到第n 1個線段樹的最後面去,抽出第n 1個線段樹的第x個元素 即 x,m 加到第x個線段樹...