题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1415
题意:一个无向图,一个猫、一只老鼠。在任意时刻猫知道老鼠在哪个顶点上。每次移动猫先。猫每次向靠近老鼠的顶点移动。若没有到达老鼠所在顶点,则接着再移动一次(即便是两次也是用的一个时间单位);然后老鼠移动;老鼠每次向周围的顶点移动或者呆在原地不动,概率相同。猫和老鼠在一个顶点上则吃掉老鼠。求吃掉老鼠的时间期望。
思路:设f[i][j][0]表示猫在i、老鼠在j、轮到猫移动的期望;f[i][j][1]表示轮到老鼠移动的期望。则对于固定的i和j,轮到猫移动时,下一次猫移动到的顶点是固定的,设为s,则f[i][j][0]=f[s][j][1]+1;对于老鼠,设与其相邻顶点集合为S,大小为num,则f[i][j][1]=(sum(f[i][Sk][0])+f[i][j][0])/(num+1)。一开始我担心会出现兜圈子的情况,就是老鼠在转,猫跟着转,这样就麻烦了,貌似需要列方程求解。但是分析一下不会出现这种情况,因为猫每次移动两个,老鼠最多移动一个,猫总能撵上老鼠的。。
vector<int> g[N];
int dis[N][N],p[N][N];
double f[N][N][2];
int n,m,S,T;
void SPFA(int u,int dis[])
{
int i;
FOR1(i,n) dis[i]=INF;
dis[u]=0;
queue<int> Q;
Q.push(u);
int visit[N]={0};
visit[u]=1;
int v;
while(!Q.empty())
{
u=Q.front();
Q.pop();
visit[u]=0;
FOR0(i,SZ(g[u]))
{
v=g[u][i];
if(dis[v]>dis[u]+1)
{
dis[v]=dis[u]+1;
if(!visit[v]) Q.push(v),visit[v]=1;
}
}
}
}
int cal(int u,int v)
{
if(u==v) return u;
int i,x,Min=INF,k;
FOR0(i,SZ(g[u]))
{
x=g[u][i];
if(dis[v][x]<Min||dis[v][x]==Min&&x<k) Min=dis[v][x],k=x;
}
if(k==v) return k;
Min=INF;
FOR0(i,SZ(g[k]))
{
x=g[k][i];
if(dis[v][x]<Min||dis[v][x]==Min&&x<u) Min=dis[v][x],u=x;
}
return u;
}
void init()
{
int i,j;
FOR1(i,n) SPFA(i,dis[i]);
FOR1(i,n) FOR1(j,n) p[i][j]=cal(i,j);
}
double DFS(int u,int v,int t)
{
if(u==v) return 0;
if(f[u][v][t]>-1) return f[u][v][t];
int i,x;
if(t==0) f[u][v][t]=DFS(p[u][v],v,1)+1;
else
{
f[u][v][t]=0;
FOR0(i,SZ(g[v]))
{
x=g[v][i];
f[u][v][t]+=DFS(u,x,0);
}
f[u][v][t]+=DFS(u,v,0);
f[u][v][t]/=SZ(g[v])+1;
}
return f[u][v][t];
}
int main()
{
RD(n,m); RD(S,T);
int i,x,y;
FOR1(i,m)
{
RD(x,y);
g[x].pb(y);
g[y].pb(x);
}
init();
clr(f,-1);
PR(DFS(S,T,0));
}