• [BZOJ1415]聪聪和可可


    Input

    数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数。 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号。 接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路。 所有的路都是无向的,即:如果能从A走到B,就可以从B走到A。 输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连。

    Output

    输出1个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。
    对于所有的数据,1≤N,E≤1000。
    对于50%的数据,1≤N≤50。

    Sample Input

    9 9
    9 3
    1 2
    2 3
    3 4
    4 5
    3 6
    4 6
    4 7
    7 8
    8 9

    Sample Output

    2.167

    题解:

    本题是一道难度适中的概率dp,其实坑点误区全部在读题上.

    首先,要注意"第一步没走到,可以再走一步";其次,还有"距离相等时走编号较小的点".

    前者保证猫一定追的上老鼠,后者则是一个决策的限制,让我们不能瞎跑题目变的难了

    既然有这个限制,n也很小,我们就可以考虑打个表预处理

    设du[i]为每个点的度

    对于猫在i点,鼠在j点的情况,设pre[i][j]为猫下一步到达的节点(即决策点)

    再设twice为猫走第一步到pre[i][j]没捉到鼠第二步的决策,则twice=pre[pre[i][j]][j]

    那么有如下情况:

    1°i==j:f[i][j]=0;

    2°pre[i][j]==j||twice==j:f[i][j]=1;

    如果1°2°均不满足,则

    3°f[i][j]=(f[twice][j]+sigma{f[twice][k],j和k间有连边}/(du[j]+1)+1

    这样本题就被解决啦,方式当然是记忆化搜索

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=1010;
    int n,m,st1,st2;
    struct node{int zhong,next;}s[N<<1];
    int e,adj[N],du[N],pre[N][N];
    inline void add(int qi,int zhong){s[++e].zhong=zhong;s[e].next=adj[qi];adj[qi]=e;}
    double f[N][N];
    inline int spfa(int st)
    {
        queue<int>q;
        int dis[N];bool vis[N];
        memset(dis,0x7f,sizeof(dis));
        memset(vis,0,sizeof(vis));
        q.push(st);pre[st][st]=st;dis[st]=0;
        while(!q.empty())
        {
            int rt=q.front();q.pop();
            for(int i=adj[rt];i;i=s[i].next)
            {
                int u=s[i].zhong;
                if(dis[u]>dis[rt]+1)
                {
                    dis[u]=dis[rt]+1;
                    if(rt==st)pre[st][u]=u;
                    else pre[st][u]=pre[st][rt];
                }
                else if(dis[u]==dis[rt]+1&&pre[st][u]>pre[st][rt])
                {
                    if(rt==st)pre[st][u]=u;
                    else pre[st][u]=pre[st][rt];
                }
                if(!vis[u])vis[u]=1,q.push(u);
            }
        }
    }
    inline double dp(int st,int ed)
    {
        if(st==ed)return f[st][ed]=0;
        int twice=pre[pre[st][ed]][ed];
        if(pre[st][ed]==ed||twice==ed)return f[st][ed]=1;
        if(f[st][ed])return f[st][ed];
        double k=1.0/(du[ed]+1);
        f[st][ed]=k*dp(twice,ed)+1;
        for(int i=adj[ed];i;i=s[i].next)
        {
            int u=s[i].zhong;
            f[st][ed]+=k*dp(twice,u);
        }
        return f[st][ed];
    }
    int main()
    {
        scanf("%d%d%d%d",&n,&m,&st1,&st2);
        int a,b;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);add(b,a);
            du[a]++,du[b]++;
        }
        for(int i=1;i<=n;i++)spfa(i);//用spfa预处理决策pre[i][j] 
        printf("%.3lf",dp(st1,st2));
    }
    Progress is not created by contented people.
  • 相关阅读:
    Python基础之迭代器、生成器
    Python基础之模块+异常
    Python基础之面向对象思维解决游戏《天龙八部》
    Oracle创建存储过程
    数据库范式
    Oracle条件判断
    Oracle的三种循环
    Oracle的pl/sql变量类型
    oracle如何实现去重和分页
    相关子查询和非相关子查询
  • 原文地址:https://www.cnblogs.com/LadyLex/p/Skyminer.html
Copyright © 2020-2023  润新知