可以先预处理出当聪聪在 i 点,可可在 j 点时,聪聪下一步到达的点的编号,记为p[i,j],bfs即可。
设f[i,j]表示聪聪在 i,可可在 j 时的期望步数,w[i,j]为与i相邻的第 j 个点编号,t[i]为 i 点的度数,则有
f[i,j]=∑t[i]k=1f[p[p[i,j],j],w[j,k]]+f[p[p[i,j],j],j]t[i]+1
然后记忆化搜索。
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#define INF 1000000000
#define N 1005
#define D double
using namespace std;
int n,m,siz,s,t;
int first[N],next[N*2],to[N*2];
int p[N],d[N],map[N][N],trans[N][N];
D f[N][N];
void inser(int x,int y)
{
next[++siz]=first[x];
first[x]=siz;
to[siz]=y;
}
void bfs(int S)
{
int head=0,tail=1;
map[p[1]=S][S]=0;
map[0][S]=INF;
while (head^tail)
{
int x=p[++head];
for (int i=first[x];i;i=next[i])
if (map[S][to[i]]==-1)
map[S][p[++tail]=to[i]]=map[S][x]+1;
}
}
void init()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for (int x,y,i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
inser(x,y),inser(y,x);
d[x]++,d[y]++;
}
memset(map,-1,sizeof(map));
for (int i=1;i<=n;i++) bfs(i);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) if (i^j)
for (int y,k=first[i];k;k=next[k])
if (map[trans[i][j]][j]>map[y=to[k]][j]||map[trans[i][j]][j]==map[y][j]&&y<trans[i][j])
trans[i][j]=y;
}
D work(int x,int y)
{
if (f[x][y]!=0) return f[x][y];
if (x==y) return 0;
if (map[x][y]<=2) return f[x][y]=1;
D ret=0;
for (int i=first[y];i;i=next[i])
ret+=work(trans[trans[x][y]][y],to[i]);
ret+=work(trans[trans[x][y]][y],y);
return f[x][y]=ret/(d[y]+1)+1;
}
int main()
{
init();
printf("%.3f",work(s,t));
return 0;
}
本文介绍了一种解决图论游戏中寻找从一个点到另一个点期望步数问题的算法。通过预处理可达路径和使用记忆化搜索技术,有效地计算出了任意两点间的最短期望路径。
430

被折叠的 条评论
为什么被折叠?



