BZOJ 1415 聪聪和可可(概率DP)

题目链接: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));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值