【BZOJ】1415 [Noi2005]聪聪和可可 期望DP+记忆化搜索

【题意】给定无向图,聪聪和可可各自位于一点,可可每单位时间随机向周围走一步或停留,聪聪每单位时间追两步(先走),问追到可可的期望时间。n<=1000。

【算法】期望DP+记忆化搜索

【题解】首先因为聪聪的步数大于可可,所以不可能出现循环,因此是DAG上的期望DP,用记忆化搜索解决。

每个点bfs预处理p[x][y]表示x走向y的第一步位置,设f[x][y]表示聪聪在x可可在y追上的期望时间。

$$f(x,y)=\sum_{z}\frac{f(g[g[i][j]]][j],z)}{out[x]+1}+1$$

其中z是y的邻点和y自身。

再判断一下一步到达,两步到达和重叠(可可随机到聪聪处)的情况即可。

复杂度O(n^2)。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1010;
struct edge{int from,v;}e[maxn*3];
int n,m,a,b,ins[maxn],first[maxn],d[maxn],q[1010],p[maxn][maxn],tot;
double f[maxn][maxn];
void insert(int u,int v)
{
    tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;ins[u]++;
    tot++;e[tot].v=u;e[tot].from=first[v];first[v]=tot;ins[v]++;
}
double dp(int a,int b)
{
    if(f[a][b])return f[a][b];
    if(a==b)return f[a][b]=0;
    if(p[a][b]==b||p[p[a][b]][b]==b)return f[a][b]=1;
    double ans=dp(p[p[a][b]][b],b);
    for(int i=first[b];i;i=e[i].from)
     ans+=dp(p[p[a][b]][b],e[i].v);
    return f[a][b]=ans/(1.0*ins[b]+1)+1;
}
void bfs(int x)
{
    memset(d,-1,sizeof(d));
    int head=0,tail=0;d[x]=0;p[x][x]=0;
    for(int i=first[x];i;i=e[i].from)p[x][e[i].v]=e[i].v,d[e[i].v]=1,q[tail++]=e[i].v;
    while(head!=tail)
     {
         int y=q[head++];if(head>1000)head=0;int num=p[x][y];
         for(int i=first[y];i;i=e[i].from)
          if(d[e[i].v]==-1||((d[y]+1==d[e[i].v])&&num<p[x][e[i].v]))
           {
               d[e[i].v]=d[y]+1;
               p[x][e[i].v]=num;
               q[tail++]=e[i].v;
               if(tail>1000)tail=0;
           }
     }
}
int main()
{
    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i=1;i<=m;i++)
     {
         int u,v;
         scanf("%d%d",&u,&v);
         insert(u,v);
     }
    for(int i=1;i<=n;i++)bfs(i);
    printf("%.3lf",dp(a,b));
    return 0;
}
View Code

 

posted @ 2018-03-06 21:20  ONION_CYC  阅读(...)  评论(...编辑  收藏