[BZOJ1415/Luogu4206][NOI2005]聪聪和可可(动态规划,期望概率,记忆化搜索)

发布于 2018-04-08  87 次阅读


本文章由SYCstudio或本站其它作者所有,请勿擅自转载

本文链接地址:[BZOJ1415/Luogu4206][NOI2005]聪聪和可可(动态规划,期望概率,记忆化搜索)

Description

在一个魔法森林里,住着一只聪明的小猫聪聪和一只可爱的小老鼠可可。虽 然灰姑娘非常喜欢她们俩,但是,聪聪终究是一只猫,而可可终究是一只老鼠, 同样不变的是,聪聪成天想着要吃掉可可。
一天,聪聪意外得到了一台非常有用的机器,据说是叫 GPS,对可可能准确 的定位。有了这台机器,聪聪要吃可可就易如反掌了。于是,聪聪准备马上出发, 去找可可。而可怜的可可还不知道大难即将临头,仍在森林里无忧无虑的玩耍。 小兔子乖乖听到这件事,马上向灰姑娘报告。灰姑娘决定尽快阻止聪聪,拯救可 可,可她不知道还有没有足够的时间。
整个森林可以认为是一个无向图,图中有 N 个美丽的景点,景点从 1 至 N 编号。小动物们都只在景点休息、玩耍。在景点之间有一些路连接。
当聪聪得到 GPS 时,可可正在景点 M(M≤N)处。以后的每个时间单位,可可 都会选择去相邻的景点(可能有多个)中的一个或停留在原景点不动。而去这些地 方所发生的概率是相等的。假设有 P 个景点与景点 M 相邻,它们分别是景点 R、 景点 S,……景点 Q,在时刻 T 可可处在景点 M,则在(T+1)时刻,可可有 1/(1 +P) 的可能在景点 R,有 1/(1 +P) 的可能在景点 S,……,有 1/(1 +P) 的可能在景点 Q,还 有1/(1 +P)的可能停在景点 M。
我们知道,聪聪是很聪明的,所以,当她在景点 C 时,她会选一个更靠近 可可的景点,如果这样的景点有多个,她会选一个标号最小的景点。由于聪聪太 想吃掉可可了,如果走完第一步以后仍然没吃到可可,她还可以在本段时间内再 向可可走近一步。
在每个时间单位,假设聪聪先走,可可后走。在某一时刻,若聪聪和可可位 于同一个景点,则可怜的可可就被吃掉了。
灰姑娘想知道,平均情况下,聪聪几步就可能吃到可可。而你需要帮助灰姑 娘尽快的找到答案。

Tag

动态规划,期望概率,记忆化搜索

解决思路

由于猫一定是向着最靠近鼠的方向移动,并且鼠移动一次时猫可以移动两次,所以猫一定是可以抓到鼠的。
设F[i][j]表示鼠在点i猫在点j猫还没有行动时猫抓到老鼠的期望。那么由于鼠当前的位置已经确定,所以猫可以直接向着最靠近鼠的位置前进两步。
这个可以预处理出来的,设Path[i][j]为鼠在i猫在j时,猫下一步走到的点的编号,这个可以把鼠放在每一个点上,以这个点为中心bfs求最短路。
接着考虑F[i][j],那么若猫在j可以经过不超过两步到达i,则F[i][j]=1,否则,扫描i的每一条出边进行等概率转移,最后还要加上鼠不动的期望。
由于转移顺序不好确定,可以采用记忆化搜索的方式实现动态规划。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

#define ll long long
#define ld long double
#define mem(Arr,x) memset(Arr,x,sizeof(Arr))

const int maxN=1010;
const int maxM=maxN*2;
const int inf=2147483647;

int n,m,S,T;
int edgecnt=0,Head[maxN],Next[maxM],V[maxM];
int Queue[maxN],Dist[maxN],Degree[maxN];
int Path[maxN][maxN];
ld F[maxN][maxN];

void Add_Edge(int u,int v);
void Bfs(int st);
ld dfs(int u,int v);

int main()
{
    mem(Head,-1);

    scanf("%d%d%d%d",&n,&m,&S,&T);
    for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) F[i][j]=-1;
    for (int i=1;i<=m;i++)
    {
        int u,v;cin>>u>>v;
        Add_Edge(u,v);Add_Edge(v,u);
    }
    for (int i=1;i<=n;i++)//预处理Path
    {
        Bfs(i);
        for (int j=1;j<=n;j++)
            if (i==j) Path[i][j]=0;
            else
            {
                Path[i][j]=inf;
                for (int e=Head[j];e!=-1;e=Next[e])
                    if (Dist[j]==Dist[V[e]]+1) Path[i][j]=min(Path[i][j],V[e]);
            }
    }
    printf("%.3LF\n",dfs(T,S));
    return 0;
}

void Add_Edge(int u,int v)
{
    edgecnt++;Next[edgecnt]=Head[u];Head[u]=edgecnt;V[edgecnt]=v;
    Degree[u]++;
    return;
}

void Bfs(int st)
{
    int h=1,t=0;mem(Dist,-1);Dist[st]=0;
    Queue[1]=st;
    do
    {
        int u=Queue[++t];
        for (int i=Head[u];i!=-1;i=Next[i])
            if (Dist[V[i]]==-1)
                Dist[Queue[++h]=V[i]]=Dist[u]+1;
    }
    while (t!=h);
    return;
}

ld dfs(int u,int v)//u-鼠,v-猫
{
    if (u==v) return F[u][v]=0;
    if ((Path[u][v]==u)||(Path[u][Path[u][v]]==u)) return F[u][v]=1;//直接抓到
    if (F[u][v]!=-1) return F[u][v];
    int now=Path[u][Path[u][v]];//猫走两步
    ld Ret=0;
    for (int i=Head[u];i!=-1;i=Next[i])//等概率转移
        Ret+=dfs(V[i],now);
    Ret+=dfs(u,now);//不动
    F[u][v]=Ret/(Degree[u]+1)+1;
    return F[u][v];
}

本文章由SYCstudio或本站其它作者所有,请勿擅自转载

本文链接地址:[BZOJ1415/Luogu4206][NOI2005]聪聪和可可(动态规划,期望概率,记忆化搜索)


HNCJ OIer