NOI2005 BZOJ 1415聪聪和可可(期望+Floyd)

这里写图片描述

一道和换教室思想差不多的题(怀疑换教室就是这个改的),老样子用Floyd算出每2个点直接的距离,然后进行期望的计算(我这里用的记忆化搜索,个人爱好,比较这样代码短)。

我们设f(i,j)为猫在i位置,老鼠在j位置的期望值(名字不想打了),如果他们在同一位置显然直接吃就好,期望为0.

同样的如果距离小于等于2,猫可以直接跑过去,期望为1.

接下来就是大于2的情况了,我们先让猫按题目描述走2步,老鼠走一步,得到位置x和y,然后我们直接询问f(x,y)就可以了。

所以方程如下:
f(i,j)=sum{f(x,y)}/t+1;
其中t为老鼠走的方案数。

详细代码如下:

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1005;
const int inf=20000005;

struct edge
{
    int u,v,next;
}e[maxn*2];
int fist[maxn]={0},cnt=0;
int d[maxn][maxn];
double f[maxn][maxn]={0};
int n,m;

void add(int x,int y)
{
    e[++cnt]=(edge){x,y,fist[x]};fist[x]=cnt;
    e[++cnt]=(edge){y,x,fist[y]};fist[y]=cnt;
}
int work(int x,int y)
{
    int z=inf,j;
    for(int k=fist[x];k;k=e[k].next)
    {
        j=e[k].v;
        if(d[j][y]>=d[x][y]) continue;
        if(j<z) z=j;
    }
    x=z;
    z=inf;
    for(int k=fist[x];k;k=e[k].next)
    {
        j=e[k].v;
        if(d[j][y]>=d[x][y]) continue;
        if(j<z) z=j;
    }
    x=z;
    return x;
}
double run(int x,int y)
{
    if(f[x][y]) return f[x][y];
    if(d[x][y]==0) return f[x][y]=0;
    if(d[x][y]<=2) return f[x][y]=1;
    int xx=work(x,y);
    int t=0,j;
    for(int k=fist[y];k;k=e[k].next)
    {
        j=e[k].v;
        t++;
        f[x][y]+=run(xx,j)+1;
    }
    f[x][y]+=run(xx,y)+1;
    t++;
    return f[x][y]/=t;
}
void init()
{
    int x,y,a,b;
    scanf("%d%d",&n,&m);
    scanf("%d%d",&a,&b);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++) if(j!=i)
    d[i][j]=inf;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        d[x][y]=d[y][x]=1;
        add(x,y);
    }
    for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)if(i!=k&&d[i][k]!=inf)
    for(int j=1;j<=n;j++)if(j!=k&&i!=j&&d[k][j]!=inf)
    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    printf("%.3lf",run(a,b));
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    init();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值