一道期望DP。
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]为i到j的期望距离,则有
d
p
[
i
]
[
j
]
=
(
d
p
[
s
[
s
[
i
]
[
j
]
]
[
j
]
]
[
v
]
+
1
)
/
(
s
i
z
e
[
j
]
+
1
)
+
1
dp[i][j] = (dp[s[s[i][j]][j]][v]+1)/(size[j]+1)+1
dp[i][j]=(dp[s[s[i][j]][j]][v]+1)/(size[j]+1)+1,其中size表示该点的出度,
s
[
i
]
[
j
]
s[i][j]
s[i][j]表示从i到j下一步走到哪,v表示i的所有一步可到达的点,对了还要包括j点本身。
最后记忆化搜索即可,注意由于每次是老鼠先走,状态转移方程应为
d
p
[
u
]
[
e
n
d
]
+
=
(
d
f
s
(
s
[
s
[
u
]
[
e
n
d
]
]
[
e
n
d
]
,
v
)
+
1
)
/
(
d
o
u
b
l
e
)
(
s
i
z
e
[
e
n
d
]
+
1
)
dp[u][end] += (dfs(s[s[u][end]][end], v) + 1) / (double)(size[end] + 1)
dp[u][end]+=(dfs(s[s[u][end]][end],v)+1)/(double)(size[end]+1)
而不是
d
p
[
u
]
[
e
n
d
]
+
=
(
d
f
s
(
s
[
s
[
u
]
[
v
]
]
[
v
]
,
v
)
+
1
)
/
(
d
o
u
b
l
e
)
(
s
i
z
e
[
e
n
d
]
+
1
)
dp[u][end] += (dfs(s[s[u][v]][v], v) + 1) / (double)(size[end] + 1)
dp[u][end]+=(dfs(s[s[u][v]][v],v)+1)/(double)(size[end]+1)。
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1001;
const int MAXM = 1001;
int fir[MAXN], nxt[MAXM << 1], to[MAXM << 1], cnt;
int size[MAXN], dis[MAXN][MAXN], s[MAXN][MAXN], vis[MAXN];
double dp[MAXN][MAXN];
inline int read(){
int k = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
return k * f;
}
inline void add_edge(int a, int b){
to[cnt] = b;
nxt[cnt] = fir[a];
fir[a] = cnt++;
}
void bfs(int begin){
queue <int> q; q.push(begin);
dis[begin][begin] = 0;
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = fir[u]; i != -1; i = nxt[i]){
int v = to[i];
if(dis[begin][v] == -1){
dis[begin][v] = dis[begin][u] + 1;
q.push(v);
}
}
}
}
double dfs(int u, int end){
if(dp[u][end] == -1){
if(u == end){
dp[u][end] = 0;
}
else if(s[u][end] == end){
dp[u][end] = 1;
}
else if(s[s[u][end]][end] == end){
dp[u][end] = 1;
}
else{
dp[u][end] = 0; //先初始化为0
for(int i = fir[end]; i != -1; i = nxt[i]){
int v = to[i];
dp[u][end] += (dfs(s[s[u][end]][end], v) + 1) / (double)(size[end] + 1);
}
dp[u][end] += (dfs(s[s[u][end]][end], end) + 1) / (double)(size[end] + 1);
}
}
return dp[u][end];
}
int main(){
freopen("in.txt", "r", stdin);
memset(fir, -1, sizeof(fir));
memset(dis, -1, sizeof(dis));
memset(s, 0x3f, sizeof(s));
int n = read(), m = read();
int C1 = read(), C2 = read();
for(int i = 1; i <= m; i++){
int a = read(), b = read();
add_edge(a, b);
add_edge(b, a);
size[a]++, size[b]++;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
dp[i][j] = -1;
}
}
for(int i = 1; i <= n; i++){
bfs(i);
}
for(int u = 1; u <= n; u++){
for(int i = fir[u]; i != -1; i = nxt[i]){
int v = to[i];
for(int j = 1; j <= n; j++){
if(dis[u][j] == dis[v][j] + 1 && s[u][j] > v){
s[u][j] = v;
}
}
}
}
//预处理i到j应该走的下一步
double Ans = dfs(C1, C2);
printf("%.3lf", Ans);
return 0;
}