题目描述
题解
这题题面有点毒
应该是求聪聪吃到可可的时间的期望
bfs处理两点之间的最短路
然后预处理出来当聪聪和可可分别在哪里的时候聪聪会向哪里走
令f(i,j)表示当某一秒开始时聪聪在i,可可在j一直到聪聪吃到可可的期望
容易知道当i=j时f(i,j)=0
当dis(i,j)<=2时f(i,j)=1
假设当聪聪在i,可可在j时聪聪会走到k,d(i)为i的度数,p=1/(d(i)+1)
那么f(i,j)=f(k,j) * p+sigma f(k,vj) * p
刚开始在纠结某两个点会互相推的问题,但是可以发现由于聪聪是不断逼近可可的,所以不可能出现两个状态互相推的情况
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
#define N 1005
int n,m,cc,kk,inf;
int tot,point[N],nxt[N*2],v[N*2];
int dis[N][N],goal[N][N];
double ans;
double d[N],f[N][N];
queue <int> q;
void add(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
}
void bfs(int s)
{
dis[s][s]=0;q.push(s);
while (!q.empty())
{
int now=q.front();q.pop();
for (int i=point[now];i;i=nxt[i])
if (dis[s][v[i]]==inf)
{
dis[s][v[i]]=dis[s][now]+1;
q.push(v[i]);
}
}
}
double dp(int cc,int kk)
{
if (f[cc][kk]>=0) return f[cc][kk];
if (cc==kk) return f[cc][kk]=0;
if (dis[cc][kk]<=2) return f[cc][kk]=1;
double P=1/(d[kk]+1.0);
f[cc][kk]=1;
int to=goal[cc][kk];
for (int i=point[kk];i;i=nxt[i])
f[cc][kk]+=P*dp(to,v[i]);
f[cc][kk]+=P*dp(to,kk);
return f[cc][kk];
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%d%d",&cc,&kk);
for (int i=1;i<=m;++i)
{
int x,y;scanf("%d%d",&x,&y);
d[x]+=1.0,d[y]+=1.0;
add(x,y),add(y,x);
}
memset(dis,127,sizeof(dis));inf=dis[0][0];
for (int i=1;i<=n;++i) bfs(i);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
{
if (dis[i][j]==inf) continue;
if (dis[i][j]<=2) {goal[i][j]=j;continue;}
int dis1=inf,id1=inf;
for (int k=point[i];k;k=nxt[k])
if (dis[v[k]][j]<dis1) dis1=dis[v[k]][j],id1=v[k];
else if (dis[v[k]][j]==dis1&&v[k]<id1) id1=v[k];
int dis2=inf,id2=inf;
for (int k=point[id1];k;k=nxt[k])
if (dis[v[k]][j]<dis2) dis2=dis[v[k]][j],id2=v[k];
else if (dis[v[k]][j]==dis2&&v[k]<id2) id2=v[k];
goal[i][j]=id2;
}
memset(f,128,sizeof(f));
ans=dp(cc,kk);
printf("%.3lf\n",ans);
}
总结
①以后做题要先看一看样例&解释