【BZOJ1415】【codevs1784】聪聪与可可,概率DP

来源:互联网 发布:安卓息屏录像软件 编辑:程序博客网 时间:2024/05/29 06:54

Time:2016.08.24
Author:xiaoyimi
转载注明出处谢谢


传送门1
传送门2
思路:
f[x][y]表示猫走到x,老鼠走到y时猫抓到老鼠的步数期望
f[x][y]>f[g[g[x][y]][y]][w[y]]
f[x][y]>f[g[g[x][y]][y]][y]
g[x][y]表示x到y的最短路径上与x相邻的编号最小的点
w[y]表示y能到达的所有点
x=y时f[x][y]=0
g[x][y]=y或g[g[x][y]][y]=y时f[x][y]=1
记忆化搜索就可以了
g数组预处理可以用SPFA+乱搞
复杂度O(n2)
代码:

#include<cstdio>#include<iostream>#include<queue>#include<cstring>#define M 1001using namespace std;int tot,n,m,S,T;int first[M],d[M],g[M][M],dis[M][M];double f[M][M];bool vis[M];int in(){    char ch=getchar();int t=0;    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();    return t;}struct edge{    int u,v,next;}e[M<<1];struct node{    int D,mi,id;};queue<int>q;void add(int x,int y){    e[++tot]=(edge){x,y,first[x]};first[x]=tot;++d[x];    e[++tot]=(edge){y,x,first[y]};first[y]=tot;++d[y];}void spfa(int x){    memset(dis[x],63,sizeof(dis[x]));    q.push(x);    dis[x][x]=0;    for (;!q.empty();q.pop())    {        int now=q.front();        for (int i=first[now];i;i=e[i].next)            if (dis[x][e[i].v]>dis[x][now]+1)            {                dis[x][e[i].v]=dis[x][now]+1,                g[x][e[i].v]=(now==x?e[i].v:g[x][now]);                if (!vis[e[i].v]) vis[e[i].v]=1,q.push(e[i].v);            }            else if (dis[x][e[i].v]==dis[x][now]+1)                g[x][e[i].v]=min(g[x][e[i].v],g[x][now]);        vis[now]=0;    }}void dfs(int x,int y){    if (f[x][y]||x==y) return;    f[x][y]=1;    if (g[x][y]==y||g[g[x][y]][y]==y) return;    double sum=0;    int z=g[g[x][y]][y];    for (int i=first[y];i;i=e[i].next)        dfs(z,e[i].v),        sum+=f[z][e[i].v];    dfs(z,y);    f[x][y]+=(sum+f[z][y])/(d[y]+1);}main(){    n=in();m=in();    S=in();T=in();    for (int i=1;i<=m;++i)        add(in(),in());    for (int i=1;i<=n;++i) spfa(i);        dfs(S,T);    printf("%.3lf\n",f[S][T]);}
0 0