[bzoj1415][NOI2005]聪聪与可可(期望+DP+Refun的胡策)

题目

传送门
这里写图片描述

题解

开始做这道题(REfun T3)的时候,想只处理链的情况,发现 有一些记忆化搜索的意味。
这里写图片描述
变量声明:
du[i] 每个节点的度
p[i][j] 猫在i 老鼠在j时猫下一步可能走的情况;
dis[i][j]:i和j两点的距离
f[i][j] 猫在i 老鼠在j时的期望值;
首先处理处上面的变量,然后记忆化搜索,

f[i][j]=(f[i][j]+dfs(p[p[i][j]][j],j))/(double)(du[j]+1)+1;

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
const int inf=2*1e9;
using namespace std;

int n,m,s,t,x,y,du[1001],p[1001][1001],dis[1001][1001];//du每个节点的度 
double f[1001][1001];

struct Edge{
    int to,next;
}edge[2001];
int head[1001],num_edge;
double ans;

void add_edge(int from,int to)
{
    edge[++num_edge].next=head[from];
    edge[num_edge].to=to;
    head[from]=num_edge;
}

int q[2001];
void bfs(int s)
{
    int front=0,tail=1;
    q[1]=s; dis[s][s]=0;
    while (front!=tail)
    {
        int now=q[++front]; 
        for (int i=head[now]; i!=0; i=edge[i].next)
        {
            int to=edge[i].to;
            if (dis[s][to] == -1)
            {
                dis[s][to]=dis[s][now]+1;
                q[++tail]=to;
            }
        }
    }
}

double dfs(int i,int j)//记忆化搜索,表示从i到j期望的时间是多少 
{
    if (f[i][j]!=-1.0) return f[i][j];
    if (i==j) return f[i][j]=0.0;//已经到达 
    if (p[i][j] == j) return f[i][j]=1.0;//还有一步 不要忘记赋值 
    if (p[p[i][j]][j] == j) return f[i][j]=1.0;//还有两步 
    f[i][j]=0.0;
    for (int k=head[j]; k!=0; k=edge[k].next)
        f[i][j]+=dfs(p[p[i][j]][j],edge[k].to);
    f[i][j]=(f[i][j]+dfs(p[p[i][j]][j],j))/(double)(du[j]+1)+1;//du[j] 
    return f[i][j];
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for (int i=1; i<=m; i++)
    {
        scanf("%d%d",&x,&y);
        add_edge(x,y); add_edge(y,x);
        du[x]++; du[y]++;
    }
    for (int i=0; i<=n; i++)
        for (int j=0; j<=n; j++)
            f[i][j]=-1;//答案数组初始化 
    memset(dis,-1,sizeof(dis));
    for (int i=1; i<=n; i++)
        bfs(i);
    memset(p,0x7f,sizeof(p));//选择编号较小的点 
    for (int i=1; i<=n; i++)
        for (int k=head[i]; k!=0; k=edge[k].next)
        {
            int to=edge[k].to;
            for (int j=1; j<=n; j++)
                if (dis[to][j]+1==dis[i][j] && p[i][j]>to)
                    p[i][j]=to;
        }
    printf("%.3lf\n",dfs(s,t));
    return 0;
}

总结

注意记忆化搜索的应用
好好学概率期望dp啊啊啊

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值