Luogu 4206 [NOI2005]聪聪与可可
BZOJ 1415
简单期望 + 记忆化搜索。
发现聪聪每一步走向的地方是在可可的所在位置确定时是确定的,设$nxt_{x, y}$表示聪聪在$x$,可可在$y$时聪聪下一步会走到哪里,我们先预处理出这个$nxt$。
为了预处理$nxt$,我们还需要先预处理一个$d_{x, y}$表示$x$到$y$的最短距离,因为所有边的边权相同,所以我们第一次广搜到一个点的时候就是到这个点的最短路。
假如$d_{x, z} == d_{y, z} + 1$,$dis(x, y) == 1$,那么$z$就是$x$到$y$最短路上的一个点,用它更新$nxt_{x, y}$即可。
我们设$f_{x, y}$ 表示聪聪在$x$,可可在$y$时抓到可可的期望步数,显然有:
$f_{x, y} == 0$ $(x == y)$
$f_{x, y} == 1$ $(nxt_{x, y} == y)$ 或者 $(nxt_{nxt_{x, y}, y} == y)$
而根据期望的性质,可可的随机行走可以表示成这个公式:
$f_{x, y} = \frac{\sum _{z} f_{nxt_{nxt_{x, y}, y}, z}}{deg_y + 1} + 1$ $z == y$或者$z$可由$y$一步走到。
记忆化搜索实现。
时间复杂度$O(n^2)$。
Code:
#include <cstdio> #include <cstring> #include <queue> using namespace std; typedef double db; const int N = 1005; const int inf = 0x3f3f3f3f; int n, m, st, ed, d[N][N]; int tot = 0, head[N], deg[N], nxt[N][N]; db f[N][N]; struct Edge { int to, nxt; } e[N << 1]; inline void add(int from, int to) { e[++tot].to = to; e[tot].nxt = head[from]; head[from] = tot; } inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9'|| ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void chkMin(int &x, int y) { if(y < x) x = y; } queue <int> Q; inline void bfs(int fir, int *dis) { Q.push(fir); for(int i = 1; i <= n; i++) dis[i] = inf; dis[fir] = 0; for(; !Q.empty(); ) { int x = Q.front(); Q.pop(); for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(dis[y] == inf) { dis[y] = dis[x] + 1; Q.push(y); } } } } db dfs(int x, int y) { if(f[x][y] != -1.0) return f[x][y]; if(x == y) return f[x][y] = 0.0; if(nxt[x][y] == y) return f[x][y] = 1.0; if(nxt[nxt[x][y]][y] == y) return f[x][y] = 1.0; db res = 0; for(int i = head[y]; i; i = e[i].nxt) { int to = e[i].to; res += dfs(nxt[nxt[x][y]][y], to); } res += dfs(nxt[nxt[x][y]][y], y); return f[x][y]= res / (deg[y] + 1) + 1; } int main() { read(n), read(m), read(st), read(ed); for(int x, y, i = 1; i <= m; i++) { read(x), read(y); add(x, y), add(y, x); deg[x]++, deg[y]++; } for(int i = 1; i <= n; i++) bfs(i, d[i]); /* for(int i = 1; i <= n; i++, printf("\n")) for(int j = 1; j <= n; j++) printf("%d ", d[i][j]); */ memset(nxt, 0x3f, sizeof(nxt)); for(int x = 1; x <= n; x++) { for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; for(int k = 1; k <= n; k++) if(d[x][k] == d[y][k] + 1) chkMin(nxt[x][k], y); } } /* for(int i = 1; i <= n; i++, printf("\n")) for(int j = 1; j <= n; j++) printf("%d ", nxt[i][j]); */ for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) f[i][j] = -1.0; dfs(st, ed); printf("%.3f\n", f[st][ed]); return 0; }