[BZOJ1415][NOI2005]聪聪和可可(概率期望+记忆化搜索)

本文探讨了一个关于两个角色——聪聪和可可在网格中移动的问题,目标是计算聪聪追上可可所需的期望时间。通过使用广度优先搜索(BFS)预处理两点间的最短距离,并设计动态规划来解决此问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

我是超链接

题解:

说是帮可可,最后还是看着聪聪把可可吃掉,灰姑娘你干啥吃的
状态还是比较容易想:f[i][j]表示聪聪在i,可可在j,聪聪吃掉可可时间期望,这样设计的基本支撑是:聪聪总是不断逼近可可,最后一定会吃掉可可。
我们可以bfs预处理出两点之间的最短距离,这样可以判断聪聪的行动了
那么几个基本的f[i][i]=0
dis[i][j]<=2,f[i][j]=1
设k为聪聪能达到的 距离j最近的 点,p=1/(du[j]+1)
f[i][j]=f[k][j]*p+Σf[k][vi]*p+1

代码:

#include <cstring>
#include <cstdio>
#include <queue>
#define INF 1e9
using namespace std;
const int N=1005;
int du[N],tot,nxt[N*2],point[N],v[N*2],dis[N][N],choose[N][N];double f[N][N];
void addline(int x,int y)
{
    ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
    ++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void bfs(int s)
{
    queue<int>q; q.push(s);
    dis[s][s]=0;
    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 x,int y)
{
    if (f[x][y]!=-1.0) return f[x][y];
    if (x==y) return f[x][y]=0.0;
    if (dis[x][y]<=2) return f[x][y]=1.0;
    f[x][y]=0;double p=1.0/(du[y]+1);int k=choose[choose[x][y]][y];
    for (int i=point[y];i;i=nxt[i])
      f[x][y]+=dp(k,v[i]);
    f[x][y]+=dp(k,y);f[x][y]*=p;f[x][y]++;
    return f[x][y];
}
int main()
{
    freopen("sb.in","r",stdin);
    int n,e,c,m;scanf("%d%d%d%d",&n,&e,&c,&m);
    for (int i=1;i<=e;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        addline(x,y);du[x]++; du[y]++;
    }
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++) f[i][j]=-1.0;
    memset(dis,0x7f,sizeof(dis));
    for (int i=1;i<=n;i++) 
      bfs(i);
    memset(choose,0x7f,sizeof(choose));//选择编号最小的,所以为max
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
      {
        if (dis[i][j]>INF) continue;
        for (int k=point[i];k;k=nxt[k])
          if (dis[i][j]==dis[v[k]][j]+1 && choose[i][j]>v[k])
            choose[i][j]=v[k];
      }
    printf("%.3lf",dp(c,m));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值