传送门
记忆化搜索。
用f[i][j]表示两个人物在i和j时的期望值。
然后枚举各种情况:
1.重合:答案为0
2.差两步之内:答案为1
3.差2步以上:走两步后的f值+1
取一个平均值就可以了。
#include<cstdlib>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=1005;
struct edge{int to,next;}e[M*2];
int head[M],deg[M],p[M][M],dis[M],q[100005],v[M],from[M];
int tot,n,m,pp,qq,x,y;
double f[M][M];
inline void add(int x,int y){
deg[x]++;
e[++tot].to=y;
e[tot].next=head[x];
head[x]=tot;
}
inline void bfs(int st){
int h=0,t=1,x;
memset(dis,1,sizeof(dis));
dis[st]=0; q[1]=st;
while (h<t){
x=q[++h];
v[x]=0;
for (int i=head[x];i;i=e[i].next)
if (dis[e[i].to]>dis[x]+1||dis[e[i].to]==dis[x]+1&&from[e[i].to]>x){
dis[e[i].to]=dis[x]+1;
from[e[i].to]=x;
if (!v[e[i].to]){
v[e[i].to]=1;
q[++t]=e[i].to;
}
}
}
for (int i=1;i<=n;i++)
if (i!=st) p[i][st]=from[i];
}
double dfs(int x,int y){
if (x==y) return 0;
if (p[x][y]==y||p[p[x][y]][y]==y) return 1;
if (f[x][y]>-1) return f[x][y];
int tmp=p[p[x][y]][y];
double p=1;
for (int i=head[y];i;i=e[i].next) p+=dfs(tmp,e[i].to)/deg[y];
return f[x][y]=p+dfs(tmp,y)/deg[y];
}
int main(){
scanf("%d%d%d%d",&n,&m,&pp,&qq);
for (int i=1;i<=n;i++) deg[i]=1;
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for (int i=1;i<=n;i++) bfs(i);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) f[i][j]=-2;
printf("%.3lf",dfs(pp,qq));
}