题目链接
http://www.lydsy.com/JudgeOnline/problem.php?id=1415
思路
根据题目要求,聪聪每次从旧点
u
移动到新点
那么我们可以根据这些特点,首先通过
显然这个DFS可以通过记忆化来优化,优化后这个做法就能AC
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define MAXE 2100
#define MAXV 1100
using namespace std;
struct edge
{
int u,v,w,next;
}edges[MAXE];
int head[MAXV],nCount=0;
void AddEdge(int U,int V,int W)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].w=W;
edges[nCount].next=head[U];
head[U]=nCount;
}
int q[MAXE*2],dist[MAXV];
bool inQueue[MAXV];
int pos[MAXV][MAXV]; //pos[i][j]=i到j的最短路上与i相邻且编号最小的点编号
double f[MAXV][MAXV]; //f[i][j]=聪聪在点i,可可在点j,聪聪抓住可可所需期望步数
void SPFA(int S)
{
memset(inQueue,false,sizeof(inQueue));
memset(dist,0x3f,sizeof(dist));
int h=0,t=0;
dist[S]=0;
for(int p=head[S];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
q[t++]=v;
dist[v]=1;
pos[S][v]=v; //!!!!!
inQueue[v]=true;
}
while(h<t)
{
int u=q[h++];
inQueue[u]=false;
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(dist[u]+edges[p].w<dist[v])
{
dist[v]=dist[u]+edges[p].w;
pos[S][v]=pos[S][u];
if(!inQueue[v])
{
q[t++]=v;
inQueue[v]=true;
}
}
else if(dist[u]+edges[p].w==dist[v]&&pos[S][u]<pos[S][v])
{
pos[S][v]=pos[S][u];
if(!inQueue[v])
{
q[t++]=v;
inQueue[v]=true;
}
}
}
}
}
void DFS(int u,int v) //求f[u][v]
{
if(f[u][v]>=0) return;
int nextu=pos[pos[u][v]][v]; //一般情况下u在下一时刻走到的位置
int cnt_child=0; //v的后继个数
double sum=0; //sum=nextu到所有v的后继的期望步数之和
if(nextu==v) //直接在下一时刻抓到了可可,那么吃到可可的期望步数就是1次
{
f[u][v]=1;
return;
}
for(int p=head[v];p!=-1;p=edges[p].next)
{
int nextv=edges[p].v;
DFS(nextu,nextv);
sum+=f[nextu][nextv];
cnt_child++;
}
DFS(nextu,v);
sum+=f[nextu][v];
cnt_child++;
f[u][v]=sum/cnt_child+1; //u到nextu走了一步,所以要加1
}
int n,m;
int main()
{
int S,T;
scanf("%d%d%d%d",&n,&m,&S,&T);
memset(head,-1,sizeof(head));
memset(f,-1,sizeof(f));
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
AddEdge(u,v,1);
AddEdge(v,u,1);
}
for(int i=1;i<=n;i++) //n次SPFA预处理出所有的pos[i][j]
{
f[i][i]=0; //相遇直接吃掉,无需移动
pos[i][i]=i;
SPFA(i);
}
DFS(S,T);
printf("%.3lf\n",f[S][T]);
return 0;
}