• BZOJ 1415 [NOI2005]聪聪与可可 (概率DP+dfs)


    题目大意:给你一个无向联通图,节点数n<=1000。聪聪有一个机器人从C点出发向在M点的可可移动,去追赶并吃掉可可,在单位时间内,机器人会先朝离可可最近的节点移动1步,如果移动一步机器人并不能吃掉可可,那机器人会再向可可的方向移动一格,如果有两个节点到可可的距离相等,那机器人会移动到编号较小的一个节点。然后可可会等可能性移动到与它的任意一个相连的节点或者原地不动(即使她明知道移动到某个节点会被吃掉)。即1/(outc[x]+1),outc为出度。求可可被吃掉时机器人走的期望时间

    概率DP记忆化+递归

    先预处理出任意两点距离

    接下来递归求答案,记录一个f[x][y]表示可可在x节点,机器人在y节点时,可可被吃掉的期望时间,x,y这种局面可能出现多次,由不同的前驱状态到达x,y这种状态,所以乘上前驱状态转移到当前状态的概率,就是这个情况对前驱状态答案的贡献。

    对于每种状态,答案都是ans=((f[x][to]+sum f[v][to])*ouc[x]+1)*prob,prob是前驱状态转移到当前状态的的概率

    时间是O(n^2)

     1 #include <queue>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #define N 1010
     6 #define mod 20100403
     7 #define p(i,j) ((i-1)*m+j)
     8 #define dd double
     9 using namespace std;
    10 
    11 char str[N][N];
    12 int n,m,s,e,cte;
    13 int inc[N],ouc[N],d[N][N],head[N],use[N];
    14 dd f[N][N];
    15 struct Edge{int to,nxt;}edge[N*10];
    16 void ae(int u,int v){
    17     ++cte,edge[cte].to=v,inc[v]++,ouc[u]++;
    18     edge[cte].nxt=head[u],head[u]=cte;
    19 }
    20 void bfs()
    21 {
    22     memset(d,0x3f,sizeof(d));
    23     for(int i=1;i<=n;i++)
    24     {
    25         d[i][i]=0;
    26         queue<int>q;
    27         q.push(i),use[i]=1;
    28         memset(use,0,sizeof(use));
    29         while(!q.empty())
    30         {
    31             int x=q.front();q.pop();
    32             for(int j=head[x];j!=-1;j=edge[j].nxt){
    33                 int v=edge[j].to;
    34                 if(d[i][v]>d[i][x]+1){
    35                     d[i][v]=d[i][x]+1;
    36                     if(!use[v]) use[v]=1,q.push(v);
    37                 }    
    38             }use[x]=0;
    39         }
    40     }
    41 }
    42 dd dfs(int x,int y,dd pb)
    43 {
    44     int vx,to1,to2;
    45     dd ans=1.0;
    46     if(f[x][y]-0.000000001>0) return f[x][y]*pb;
    47     if(!d[x][y]) {f[x][y]=0;return 0;}
    48     if(d[x][y]<=2) {f[x][y]=1.0;return pb*1.0;}
    49     to1=y;
    50     for(int j=head[y];j!=-1;j=edge[j].nxt){
    51         int v=edge[j].to;
    52         if(d[x][v]<d[x][to1]) to1=v;
    53         else if(d[x][v]==d[x][to1]) to1=min(v,to1);
    54     }
    55     to2=to1;
    56     for(int j=head[to1];j!=-1;j=edge[j].nxt){
    57         int v=edge[j].to;
    58         if(d[x][v]<d[x][to2]) to2=v;
    59         else if(d[x][v]==d[x][to2]) to2=min(v,to2);
    60     }
    61     for(int j=head[x];j!=-1;j=edge[j].nxt){
    62         vx=edge[j].to;
    63         ans+=dfs(vx,to2,1.0/(1.0*ouc[x]+1.0));
    64     }
    65     ans+=dfs(x,to2,1.0/(1.0*ouc[x]+1.0)); 
    66     f[x][y]=ans;
    67     return ans*pb;
    68 }
    69 
    70 int main()
    71 {
    72     scanf("%d%d%d%d",&n,&m,&s,&e);
    73     int x,y;memset(head,-1,sizeof(head));    
    74     for(int i=1;i<=m;i++)
    75         scanf("%d%d",&x,&y),
    76         ae(x,y),ae(y,x);
    77     bfs();
    78     printf("%.3lf
    ",dfs(e,s,1.0));
    79     return 0;
    80 }
  • 相关阅读:
    Orika对象复制教程(完美笔记)
    JAVA-开发构建Gradle项目安装使用教程
    Java中传入一个时间范围,取出该时间范围内所有日期的集合
    线程安全之原子操作
    Java内存模型以及线程安全的可见性问题
    Java线程池的应用
    Java中实现线程的方式
    线程通信
    线程状态
    CPU缓存和内存屏障
  • 原文地址:https://www.cnblogs.com/guapisolo/p/9743171.html
Copyright © 2020-2023  润新知