题目大意:给你一个无向联通图,节点数n<=1000。聪聪有一个机器人从C点出发向在M点的可可移动,去追赶并吃掉可可,在单位时间内,机器人会先朝离可可最近的节点移动1步,如果移动一步机器人并不能吃掉可可,那机器人会再向可可的方向移动一格,如果有两个节点到可可的距离相等,那机器人会移动到编号较小的一个节点。然后可可会等可能性移动到与它的任意一个相连的节点或者原地不动(即使她明知道移动到某个节点会被吃掉)。即1/(outc[x]+1),outc为出度。求可可被吃掉时机器人走的期望时间
概率DP记忆化+递归
先预处理出任意两点距离
接下来递归求答案,记录一个f[x][y]表示可可在x节点,机器人在y节点时,可可被吃掉的期望时间,x,y这种局面可能出现多次,由不同的前驱状态到达x,y这种状态,所以乘上前驱状态转移到当前状态的概率,就是这个情况对前驱状态答案的贡献。
对于每种状态,答案都是,prob是前驱状态转移到当前状态的的概率
时间是
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 1010
#define mod 20100403
#define p(i,j) ((i-1)*m+j)
#define dd double
using namespace std; char str[N][N];
int n,m,s,e,cte;
int inc[N],ouc[N],d[N][N],head[N],use[N];
dd f[N][N];
struct Edge{int to,nxt;}edge[N*];
void ae(int u,int v){
++cte,edge[cte].to=v,inc[v]++,ouc[u]++;
edge[cte].nxt=head[u],head[u]=cte;
}
void bfs()
{
memset(d,0x3f,sizeof(d));
for(int i=;i<=n;i++)
{
d[i][i]=;
queue<int>q;
q.push(i),use[i]=;
memset(use,,sizeof(use));
while(!q.empty())
{
int x=q.front();q.pop();
for(int j=head[x];j!=-;j=edge[j].nxt){
int v=edge[j].to;
if(d[i][v]>d[i][x]+){
d[i][v]=d[i][x]+;
if(!use[v]) use[v]=,q.push(v);
}
}use[x]=;
}
}
}
dd dfs(int x,int y,dd pb)
{
int vx,to1,to2;
dd ans=1.0;
if(f[x][y]-0.000000001>) return f[x][y]*pb;
if(!d[x][y]) {f[x][y]=;return ;}
if(d[x][y]<=) {f[x][y]=1.0;return pb*1.0;}
to1=y;
for(int j=head[y];j!=-;j=edge[j].nxt){
int v=edge[j].to;
if(d[x][v]<d[x][to1]) to1=v;
else if(d[x][v]==d[x][to1]) to1=min(v,to1);
}
to2=to1;
for(int j=head[to1];j!=-;j=edge[j].nxt){
int v=edge[j].to;
if(d[x][v]<d[x][to2]) to2=v;
else if(d[x][v]==d[x][to2]) to2=min(v,to2);
}
for(int j=head[x];j!=-;j=edge[j].nxt){
vx=edge[j].to;
ans+=dfs(vx,to2,1.0/(1.0*ouc[x]+1.0));
}
ans+=dfs(x,to2,1.0/(1.0*ouc[x]+1.0));
f[x][y]=ans;
return ans*pb;
} int main()
{
scanf("%d%d%d%d",&n,&m,&s,&e);
int x,y;memset(head,-,sizeof(head));
for(int i=;i<=m;i++)
scanf("%d%d",&x,&y),
ae(x,y),ae(y,x);
bfs();
printf("%.3lf\n",dfs(e,s,1.0));
return ;
}