[BZOJ1415][Noi2005]聪聪和可可(bfs+概率期望+记搜)

来源:互联网 发布:pg报丧女妖网络限定 编辑:程序博客网 时间:2024/06/04 06:23

题目描述

传送门

题解

这题题面有点毒
应该是求聪聪吃到可可的时间的期望

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 1005int 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);}

总结

①以后做题要先看一看样例&解释

0 0
原创粉丝点击