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

期望相关:

  数学期望,可以简单理解的加权平均数。设有一系列的值xi,每个值被取到的概率为pi,则期望E=i=1npixi

  期望具有线性性: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=yf[x][y]=0;当0<dis[x][y]2f[x][y]=1

 当dis[x][y]>2时,f[x][y]=f[p[x][y]][y]+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\n",ans);
62     return 0;
63 }
复制代码

 

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

 

posted @   羊毛羊  阅读(350)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示