概率dp 入门
来源:互联网 发布:速记用什么软件 编辑:程序博客网 时间:2024/05/18 19:42
有dp就一定有状态和状态转移,不同的就是概率dp处理的是概率或者期望
不知道该说点什么,就贴贴代码了。
A - Scout YYF I
经典的跳地雷的题目,有p的概率往前走一步,有1-p的概率跳两格,求安全越过所有地雷的概率,这题由于数据量较大,推出公式后用矩阵快速幂做,poj的G++printf需要用%f才能过。。。
#include<cstdio>#include<string.h>#include<algorithm>#include<iostream>using namespace std;typedef long long ll;const int maxn = 105;const int maxe=300;const int inf = 0x3f3f3f3f;const int mod=1000000007;int n,k,m;double p;double dp[maxn];int place[maxn];struct matrix{ double ju[2][2]; matrix(){memset(ju,0,sizeof(ju));} matrix operator *(matrix b){ matrix cnt; for(int i=0;i<2;i++){ for(int j=0;j<2;j++){ for(int k=0;k<2;k++){ cnt.ju[i][j]+=ju[i][k]*b.ju[k][j]; } } } return cnt; } void operator=(matrix b){ for(int i=0;i<2;i++){ for(int j=0;j<2;j++)ju[i][j]=b.ju[i][j]; } }};double pow_mod(double a,double b,int c){ matrix cc; cc.ju[0][0]=p,cc.ju[0][1]=1-p; cc.ju[1][0]=1;cc.ju[1][1]=0; matrix ans; ans.ju[0][0]=1;ans.ju[0][1]=0; ans.ju[1][0]=0;ans.ju[1][1]=1; int kkk=1; while(c){ if(c%2)ans=ans*cc; c/=2; cc=cc*cc; } return a*ans.ju[0][0]+b*ans.ju[0][1];}int main(){ while(cin>>n>>p){ memset(dp,0,sizeof(dp)); for(int i=1;i<=n;i++){ cin>>place[i]; } sort(place+1,place+1+n); if(place[1]==0)dp[0]=0; else dp[0]=1; int cnt=1; for(int i=1;i<=n;i++){ double kk; int step=place[i]-1-cnt; if(step<0){dp[i]=0;break;} if(step==0){kk=dp[i-1];} else if(step==1){kk=dp[i-1]*p;} else{ kk=pow_mod(dp[i-1]*p,dp[i-1],step-1); } dp[i]=kk*(1-p); cnt=place[i]+1; } printf("%.7f\n",dp[n]); } return 0;}
B - Collecting Bugs
找bug,有n种bug和m个子系统,每天可以找到一个bug,但是bug的种类和所处于子系统的概率都是均等的,求找到所有种类的bug以及在所有子系统种都找到bug的期望时间。
注意边界处理
#include <string.h>#include<cstdio>using namespace std;const int maxn=1005;int n,m;double dp[maxn][maxn];bool vis[maxn][maxn];double DP(int a,int b){ if(vis[a][b])return dp[a][b]; double ans=0; int k1=n-a,k2=m-b; if(k1&&k2) ans+=double(k1)/n*k2/m*(1+DP(a+1,b+1)); if(k1&&b) ans+=double(k1)/n*double(b)/m*(1+DP(a+1,b)); if(k2&&a) ans+=double(k2)/m*double(a)/n*(1+DP(a,b+1)); if(a&&b){ double p4=double(a)/n*b/m; ans+=p4; ans/=(1.0-p4); } vis[a][b]=1; return dp[a][b]=ans;}int main(){ while(~scanf("%d%d",&n,&m)){ memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); vis[n][m]=1; printf("%.4f\n",DP(0,0)); } return 0;}
C - One Person Game
摇骰子,若三个骰子的点数分别为a,b,c,则分数归零,否则分数+=a=b=c,分数大于等于n游戏结束,求游戏结束的期望时间
因为每一个状态都可能转移到分数为0的状态,所以不能像之前那样求了,得从公式中推出通式。
#include <string.h>#include<cstdio>using namespace std;const int maxn=605;const int maxm=35;int n,k1,k2,k3,a,b,c;double p0;double p[6*6*6+5];double A[maxn],B[maxn];int main(){ int t; scanf("%d",&t); while(t--){ memset(p,0,sizeof(p)); scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c); p0=1.0/k1/k2/k3; for(int i=1;i<=k1;i++) for(int j=1;j<=k2;j++) for(int k=1;k<=k3;k++) if(!(i==a&&j==b&&k==c)) p[i+j+k]+=p0; memset(A,0,sizeof(A)); memset(B,0,sizeof(B)); for(int i=n;i>=0;i--){ A[i]=p0;B[i]=1; for(int j=1;j<=k1+k2+k3;j++){ A[i]+=A[i+j]*p[j]; B[i]+=B[i+j]*p[j]; } } printf("%.16lf\n",B[0]/(1-A[0])); } return 0;}
D - Aeroplane chess
飞行棋,还有连接飞行线可以直接到另一个点,不过状态转移还是很简单的。
#include<cstdio>#include<string.h>#include<cmath>using namespace std;typedef long long ll;const int maxn=100005;const int maxm=20005;int n,m;double dp[maxn];bool vis[maxn];bool line[maxn];int to[maxn];double DP(int i){ if(i>=n)return 0; if(vis[i])return dp[i]; if(line[i]){vis[i]=1;return dp[i]=DP(to[i]);} double ans=0; for(int j=1;j<=6;j++){ ans+=1/6.0*(1+DP(i+j)); } vis[i]=1; return dp[i]=ans;}int main(){ int x,y; while(~scanf("%d%d",&n,&m),n+m){ memset(line,0,sizeof(line)); for(int i=0;i<m;i++){ scanf("%d%d",&x,&y); line[x]=1;to[x]=y; } memset(vis,0,sizeof(vis)); memset(dp,0,sizeof(dp)); printf("%.4lf\n",DP(0)); } return 0;}
G - LOOPS
逃离迷宫的期望题,每一个grid都有一定概率传送到右边,上边或者自身grid,问从左下角到右上角逃脱的期望。
#include<cstdio>#include<string.h>#include<cmath>using namespace std;typedef long long ll;const int maxn=1005;const int maxm=20005;int r,c;double p[maxn][maxn][3];double dp[maxn][maxn];bool vis[maxn][maxn];double DP(int i,int j){ if(i<0||j<0)return 0; if(vis[i][j])return dp[i][j]; double ans=0; if(p[i][j][1]) ans+=p[i][j][1]*(2+DP(i,j+1)); if(p[i][j][2]) ans+=p[i][j][2]*(2+DP(i+1,j)); if(p[i][j][0]){ ans+=2*p[i][j][0]; ans/=(1-p[i][j][0]); } vis[i][j]=1; return dp[i][j]=ans;}int main(){ while(~scanf("%d%d",&r,&c)){ for(int i=0;i<r;i++){ for(int j=0;j<c;j++){ for(int k=0;k<3;k++) scanf("%lf",&p[i][j][k]); } } memset(vis,0,sizeof(vis)); memset(dp,0,sizeof(dp)); dp[r-1][c-1]=0; vis[r-1][c-1]=1; for(int i=0;i<r;i++){ for(int j=0;j<c;j++){ DP(i,j); } } printf("%.3lf\n",dp[0][0]); } return 0;}
H - Check the difficulty of problems
给出每个队伍ac每一题的概率,求冠军队伍(可以不止一支)出n题以上,其他队伍都出1题以上的概率。
求出每个队伍i出j题的概率,然后前缀和得到每个队伍i做出0到j题的概率,然后就可以得到所有队伍都a一道题以上的概率了,然后又可以求出所有队伍都出n题以下的概率,减一下就得到答案了。
#include <string.h>#include<cstdio>using namespace std;const int maxn=1000;const int maxm=35;int n,t,m;double p[maxn][maxm];double dp[maxn][maxm][maxm];double s[maxn][maxm];int main(){ while(scanf("%d%d%d",&m,&t,&n),m+t+n){ memset(dp,0,sizeof(dp)); memset(s,0,sizeof(s)); for(int i=0;i<t;i++){ for(int j=1;j<=m;j++){ scanf("%lf",&p[i][j]); } dp[i][0][0]=1; } for(int i=0;i<t;i++){ for(int j=1;j<=m;j++){ for(int k=0;k<=j;k++){ if(j) dp[i][j][k]=dp[i][j-1][k-1]*p[i][j]+dp[i][j-1][k]*(1-p[i][j]); else dp[i][j][k]=dp[i][j-1][k]*(1-p[i][j]); } } } for(int i=0;i<t;i++){ s[i][0]=dp[i][m][0]; for(int j=1;j<=n;j++){ s[i][j]=s[i][j-1]+dp[i][m][j]; } } double pp=1; for(int i=0;i<t;i++){ pp*=1-s[i][0]; } double pp2=1; for(int i=0;i<t;i++){ pp2*=s[i][n-1]-s[i][0]; } printf("%.3lf\n",pp-pp2); } return 0;}
I - Bag of mice
两个人轮流抓老鼠,知道怎么转移状态就行了。
#include<iostream>#include<algorithm>#include<string.h>#include<string>#include<cmath>#include<stdio.h>using namespace std;int w,b;double v[1005][1005];double dfs(int white,int black){ if(white==0)return 0.0;//only black else if(black==0){return 1.0;}//only white if(v[white][black]!=0)return v[white][black]; double win=0; double cw=double(white)/double(white+black); win+=double(white)/double(white+black);//gongzhuchoubai cw=(1.0-cw)*double(black-1)/double(white+black-1);//mowang chou hei double cnt=0.0; if(black>=3){ cnt+=dfs(white,black-3)*(double(black-2)/double(black+white-2)); } if(white>=1&&black>=2){ cnt+=dfs(white-1,black-2)*(double(white)/double(black+white-2)); } win+=cw*cnt; v[white][black]=win; return win;}int main(){ scanf("%d%d",&w,&b); printf("%.9lf",dfs(w,b)); return 0;}
J - Football
足球比赛,求某队成为冠军的概率最大,需要注意的就是某个队伍i在第j轮可以遇到的对手是那些队伍(因为赛制原因),dp[i][j]表示队伍i在第j轮获胜的概率。
#include<cstdio>#include<string.h>#include<cmath>using namespace std;typedef long long ll;const int maxn=105;const int maxm=20005;int n,m;int total;double p[200][200];double dp[200][10];bool vis[200][200];double DP(int i,int j){ if(vis[i][j])return dp[i][j]; double ans=0; int cnt=pow(2,j); int last=pow(2,j-1); int k1=i/last; int kk=i/cnt; for(int z=kk*cnt;z<(kk+1)*cnt;z++){ if(z>=k1*last&&z<(k1+1)*last)continue; ans+=DP(z,j-1)*p[i][z]; } ans*=dp[i][j-1]; vis[i][j]=1; return dp[i][j]=ans;}int main(){ while(scanf("%d",&n),n!=-1){ memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); total=pow(2,n); for(int i=0;i<total;i++){ dp[i][0]=1; vis[i][0]=1; for(int j=0;j<total;j++){ scanf("%lf",&p[i][j]); } } for(int j=1;j<=n;j++){ for(int i=0;i<total;i++){ DP(i,j); } } int winner=-1; double g=0; for(int i=0;i<total;i++){ if(dp[i][n]>g){ g=dp[i][n]; winner=i+1; } } printf("%d\n",winner); } return 0;}
K - Kids and Prizes
从礼物的角度来看,只有拿或者被拿两种状态,所有孩子选房间的概率都是相等不变的,所以每一个礼物被拿走的概率都相等,其实就变成了n重伯努利实验了,然后期望就是np
M - Help Me Escape
简单期望题。
#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=105;const int maxm=20005;int n,l;double p;int t[maxn];int c[maxn];double dp[maxm];double cal(int cnt){ if(dp[cnt])return dp[cnt]; double ans=0; for(int i=0;i<n;i++){ if(cnt>c[i]){ ans+=t[i]*p; } else{ ans+=(1+cal(cnt+c[i]))*p; } } return dp[cnt]=ans;}int main(){ while(~scanf("%d%d",&n,&l)){ for(int i=0;i<n;i++){ scanf("%d",&c[i]); t[i]=(sqrt(double(5))+1)/2.0*c[i]*c[i]; } p=1.0/n; memset(dp,0,sizeof(dp)); printf("%.3lf\n",cal(l)); } return 0;}
- 概率DP【入门】
- HDU4405概率DP入门
- hdu4405概率dp入门
- 概率dp入门
- 概率DP入门题
- 【概率DP入门】
- 概率DP入门
- poj2096 概率dp入门
- 概率DP入门小结
- 概率dp 入门
- zoj_3822_概率dp入门
- 概率DP入门大集合
- 概率DP入门大集合
- 概率DP —— 入门
- poj2096之概率DP入门
- hdu3853之概率dp入门
- ACM-概率dp之入门
- POJ 2096 概率DP入门
- Spring---IOC(控制反转)和DI(依赖注入)
- mysql5启动报错:本地计算机 上的 MySQL 服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止
- 让IE6 IE7 IE8 IE9 IE10 IE11支持Bootstrap的解决方法
- Android 基于 Speex 的高度封装语音库,0 耦合,没三方jar包
- 四大内置核心函数式接口
- 概率dp 入门
- Exception和RuntimeException的区别
- 深入理解findViewById原理
- 《统计学习方法》笔记08:boosting(1)
- CentOS7安装JDK1.8
- ++在前和++在后
- python实现对矩阵按照行、列求和,不使用numpy、pandas模块
- CentOS 6.9系统下Docker的安装配置详解
- volatile 关键字