概率dp入门的简单题(hdu 4405,牡丹江,codeforces)
2015-05-07 23:58
543 查看
最近学习了一下概率dp,感觉没有想象中的那么难。主要还是状态的转移方程的构建。
对于”求概率正推,求期望反推“这句话有了初步的理解。期望的意思是说你现在处在一个状态,还需要几步到达最终状态,这是一个期望值,
假如我现在已经在目标状态,那么期望是0,即解决了初始化的问题,否则并不知道起点的期望值。
附上几道入门题:
hdu 4405 http://acm.hdu.edu.cn/showproblem.php?pid=4405
题意:飞行棋,每次掷骰子,向前移动的距离是当前位置+骰子的点数(1~6),还有一些直达点,求由0到n的掷骰子次数的期望。
逆推。从终点逆推回来,状态的转移看文中代码把。
题意:n*m的棋盘,每天放置一枚棋子,求每行每列都至少有一颗棋子的期望天数。
概率dp的裸题,但是要注意细节的处理。我们设dp[i][j][k]是第k天可以控制i行j列的概率,则状态的转移,k+1天要么还是控制i行j列,要么是i+1,j或者i,j+1,或者i+1,j+1
最后的最大天数一定是n*m-min(n,m)+1。
codefores D:
题意:给出石头、剪刀、布的个数,每次两个不同的会遇见,问经过足够长的时间后,分别单独留在场上的概率。
用dp[i][j][k]分别表示场上剩下的石头、剪刀、布的个数,根据代码中状态转移方程,最后只要场上 目标对象的 敌人为0时,求出概率和即是最终的获胜概率。
对于”求概率正推,求期望反推“这句话有了初步的理解。期望的意思是说你现在处在一个状态,还需要几步到达最终状态,这是一个期望值,
假如我现在已经在目标状态,那么期望是0,即解决了初始化的问题,否则并不知道起点的期望值。
附上几道入门题:
hdu 4405 http://acm.hdu.edu.cn/showproblem.php?pid=4405
题意:飞行棋,每次掷骰子,向前移动的距离是当前位置+骰子的点数(1~6),还有一些直达点,求由0到n的掷骰子次数的期望。
逆推。从终点逆推回来,状态的转移看文中代码把。
//hdu 4405 #include<iostream> #include<string> #include<cstring> #include<algorithm> #include<iomanip> using namespace std; int _hash[100010]; double dp[100010]; int main() { int n,m,x,y; while(cin>>n>>m) { if(n==0&&m==0) break; memset(_hash,-1,sizeof(_hash)); for(int i=1;i<=m;i++) { cin>>x>>y; _hash[x]=y; } memset(dp,0,sizeof(dp));//初始值dp =0 for(int i=n-1;i>=0;i--) { if(_hash[i]!=-1) dp[i]=dp[_hash[i]];//走捷径 else { for(int j=1;j<=6;j++) dp[i]+=1.0/6*(dp[i+j]+1);//到达i的状态是由(i+1....i+6)来的 } } cout<<setiosflags(ios::fixed)<<setprecision(4)<<dp[0]<<endl; } return 0; }牡丹江现场赛的一道棋盘问题: http://acm.hust.edu.cn/vjudge/contest/view.action?cid=77292#problem/C
题意:n*m的棋盘,每天放置一枚棋子,求每行每列都至少有一颗棋子的期望天数。
概率dp的裸题,但是要注意细节的处理。我们设dp[i][j][k]是第k天可以控制i行j列的概率,则状态的转移,k+1天要么还是控制i行j列,要么是i+1,j或者i,j+1,或者i+1,j+1
最后的最大天数一定是n*m-min(n,m)+1。
//牡丹江棋盘问题 #include<iostream> #include<string> #include<cstring> #include<iomanip> #include<algorithm> #include<cmath> using namespace std; double dp[55][55][55*55]; int T,n,m; double ans; int main() { cin>>T; while(T--) { cin>>n>>m; memset(dp,0,sizeof(dp)); int pmax=n*m-min(n,m)+1;//最终需要的最大天数 dp[1][1][1]=1.0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { for(int k=max(i,j);k<=i*j;k++) { if(i==n&&j==m)//及时跳出 break; dp[i][j][k+1]+=dp[i][j][k]*(i*j-k)/(n*m-k); dp[i+1][j][k+1]+=dp[i][j][k]*(n-i)*j/(n*m-k); dp[i][j+1][k+1]+=dp[i][j][k]*(m-j)*i/(n*m-k); dp[i+1][j+1][k+1]+=dp[i][j][k]*(n-i)*(m-j)/(n*m-k); } } } ans=0.0; int p=max(n,m); for(int i=p;i<=pmax;i++) ans+=dp [m][i]*i;//天数*概率 cout<<setiosflags(ios::fixed)<<setprecision(12)<<ans<<endl; } return 0; }
codefores D:
题意:给出石头、剪刀、布的个数,每次两个不同的会遇见,问经过足够长的时间后,分别单独留在场上的概率。
用dp[i][j][k]分别表示场上剩下的石头、剪刀、布的个数,根据代码中状态转移方程,最后只要场上 目标对象的 敌人为0时,求出概率和即是最终的获胜概率。
//D: #include<iostream> #include<iomanip> using namespace std; double dp[101][101][101]; int main() { int a,b,c; cin>>a>>b>>c; dp[a][b][c]=1.0; for(int i=a;i>=1;i--) for(int j=b;j>=1;j--) for(int k=c;k>=1;k--) { if(dp[i][j][k]==0) continue; int tot=i*j+i*k+j*k; //总的情况 dp[i-1][j][k]+=i*k*1.0/tot*dp[i][j][k]; dp[i][j-1][k]+=j*i*1.0/tot*dp[i][j][k]; dp[i][j][k-1]+=k*j*1.0/tot*dp[i][j][k]; } double ans=0; for(int i=1;i<=a;i++) for(int j=0;j<=b;j++) ans+=dp[i][j][0]; cout<<setiosflags(ios::fixed)<<setprecision(12)<<ans; ans=0; for(int i=1;i<=b;i++) for(int j=0;j<=c;j++) ans+=dp[0][i][j]; cout<<" "<<setiosflags(ios::fixed)<<setprecision(12)<<ans; ans=0; for(int i=1;i<=a;i++) for(int j=1;j<=c;j++) ans+=dp[i][0][j]; cout<<" "<<setiosflags(ios::fixed)<<setprecision(12)<<ans<<endl; }
相关文章推荐
- hdu 4405 简单概率dp
- 简单概率DP——hdu4405
- 简单概率dp(期望)-hdu-4405-Aeroplane chess
- 概率DP求期望入门,HDU 4405,POj 2096,HDU 3853
- HDU 4405 Aeroplane chess(概率DP入门)
- hdu 4405 Aeroplane chess 概率dp入门题
- hdu 4405(概率dp简单题)
- hdu 4405 Aeroplane chess(简单概率dp 求期望)
- hdu 4405 Aeroplane chess(概率dp)
- 概率DP:飞行棋hdu4405
- HDU 4405 - Aeroplane chess (概率DP 求期望)
- hdu 4405 概率dp
- HDU-4405 Aeroplane chess(概率DP求期望)
- hdu 4405 概率dp 求期望
- HDU 4405 Aeroplane chess (概率-期望DP)【模板】
- Hdu 4405 Aeroplane chess - 简单DP
- hdu 4405 Aeroplane chess(概率dp1)
- hdu 4405 飞行棋 概率dp
- hdu 4405 概率DP
- hdu 4405 Aeroplane chess 概率dp