概率/期望DP初步——BZOJ1415 聪聪和可可

期望相关:

  数学期望,可以简单理解的加权平均数。设有一系列的值$x_i$,每个值被取到的概率为$p_i$,则期望$E=sumlimits_{i=1}^n p_i x_i$。

  期望具有线性性:$$E(aX+bY)=aE(X)+bE(Y)$$ $$E(XY)=E(X)E(Y)$$ 大概就是说求期望的时候正着反着乱序着乱搞求出来的都是对的。。。

基于期望的线性性,我们可以在概率和期望之间建立一定的递推关系,这样就可以通过动态规划来解决一些概率问题。

比如NOI2005的聪聪和可可。

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇。

设聪聪在节点$x$,可可在节点$y$

设$f[u][v]$为聪聪在$u$可可在$v$时聪聪抓住可可的期望时间,$p[u][v]$为为聪聪在$u$可可在$v$时聪聪下一步会到达的节点,$degree[v]$为节点$v$的度;

显然,当$x=y$时$f[x][y]=0$;当$0<dis[x][y] leqslant 2$时$f[x][y]=1$。

 当$dis[x][y]>2$时,$$f[x][y]=frac{f[p[x][y]][y]+sumlimits_{e(y,k)} f[p[x][y]][k]}{degree[x]+1}$$

对每个节点进行一次SPFA求出p[][]

然后根据上述状态转移方程记忆化搜索就好。

 1 #include<cstring>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstdio>
 5 #include<queue>
 6 #define foru(i,x,y) for(int i=x;i<=y;i++)
 7 using namespace std;
 8 const int N=1e4+10;
 9 struct edge{int to,nxt;}e[N*2];
10 queue<int> q;
11 int head[N],vis[N],d[N],ne,n,m,s,t,p[1005][1005];
12 double f[1005][1005];
13 void add(int a,int b){e[++ne]=(edge){b,head[a]};head[a]=ne;}
14 void spfa(int x){
15     memset(d,127,sizeof(d));
16     memset(vis,0,sizeof(vis));
17     q.push(x);d[x]=0;vis[x]=1;
18     while(!q.empty()){
19         int k=q.front();q.pop();
20         vis[k]=0;
21         for(int i=head[k];i;i=e[i].nxt){
22             int v=e[i].to;
23             if(d[v]>d[k]+1||(d[v]==d[k]+1&&k<p[v][x])){
24                 d[v]=d[k]+1;
25                 p[v][x]=k;
26                 if(!vis[v]){
27                     q.push(v);
28                     vis[v]=1;
29                 }
30             }
31         }
32     }
33 }
34 
35 double dfs(int x,int y){
36     if(f[x][y]!=-1)return f[x][y];
37     if(x==y){f[x][y]=0;return 0;}
38     if(p[x][y]==y||p[p[x][y]][y]==y){f[x][y]=1;return 1;};
39     f[x][y]=dfs(p[p[x][y]][y],y);int d=0;
40     for(int i=head[y];i;i=e[i].nxt){
41         d++;
42         int v=e[i].to;
43         f[x][y]+=dfs(p[p[x][y]][y],v);
44     }
45     (f[x][y]/=d+1);
46     f[x][y]+=1;
47     return f[x][y];
48 }
49 
50 int main(){
51     int u,v;
52     scanf("%d%d",&n,&m);
53     scanf("%d%d",&s,&t);
54     foru(i,1,m){
55         scanf("%d%d",&u,&v);
56         add(u,v);add(v,u);
57     }
58     foru(i,1,n)foru(j,1,n)f[i][j]=-1;
59     foru(i,1,n)spfa(i);
60     double ans=dfs(s,t);
61     printf("%.3lf
",ans);
62     return 0;
63 }

DP一直是弱项,总是找不到套路,还是多做点题吧。

原文地址:https://www.cnblogs.com/y-m-y/p/6773867.html