概率DP专题 (更新中)

来源:互联网 发布:安卓7.0 电量优化 编辑:程序博客网 时间:2024/05/29 15:29

点击打开链接

POJ  3071 FOOTBALL

题意:n<=7 2^n个人,知道p[i][j]:i打败j的概率.1和2比,3-4比..胜利者进入下一轮继续,问获胜概率最大是谁? 
设dp[i][j]第i个人赢j轮的概率 dp[i][j]+=dp[i][j-1]*dp[k][j-1]*p[i][k]  k范围? 

利用位运算来推导:2^n个人对应一棵二叉树,从下数第j层代表轮数,若第i个人在第j层的左子树中 则j层的右子树结点都可以在第j轮作为i的对手

找到规律 i>>(j-1)^1==k>>(j-1)  i,k表示第j层中的左右子树的中某个结点

#include <iostream>#include <algorithm>#include <cstring>#include <queue>#include <cstdio>#include <map>#include <vector>using namespace std;const int N=2e3+20;const int inf=2e8;double dp[N][N];//dp[i][j]第i个人赢j轮的概率double p[N][N]; int main(){int n; while(cin>>n&&n!=-1)   { int m=1<<n; for(int i=0;i<m;i++) for(int j=0;j<m;j++) scanf("%lf",&p[i][j]); int s,e; memset(dp,0,sizeof(dp));for(int i=0;i<m;i++)dp[i][0]=1.0;for(int j=1;j<=n;j++){for(int i=0;i<m;i++){for(int k=0;k<m;k++){//相邻 if(((i>>(j-1))^1)==(k>>(j-1)))dp[i][j]+=dp[i][j-1]*dp[k][j-1]*p[i][k];}}} double res=0;int ans;for(int i=0;i<m;i++){if(dp[i][n]>res)res=dp[i][n],ans=i+1;}cout<<ans<<endl;}return 0;}


POJ  2151 Check the difficulty of Problems 

题意:T只队伍,m个问题,T<=1000,m<=30,p[i][j] 第i人解决问题j的概率,问冠军至少答对n题并且所有人都至少答对一题的概率?
P1:所有人都至少对一题 等于第i个人至少对一题累乘,求每个i时利用对立事件(1-对0题的概率)即可 
P2:所有人对的题目1<=x<=n-1的概率
P2为P1的子集 P1-P2为所有人都至少对一题 && 至少存在一个人(冠军)答题数>=n 
dp[k][i][j]第k个人前i题对j题的概率 

m*t<=3e4 暴力枚举第i人 答对的题为1~n-1 即可计算出P2 

#include <iostream>#include <algorithm>#include <cstring>#include <queue>#include <cstdio>#include <map>#include <vector>using namespace std;const int N=1e3+20;const int inf=2e8;double dp[N][35][35];//dp[k][i][j]第k个人前i题对j题的概率double p[N][N];int m,t,n;int main(){while(cin>>m>>t>>n&&(m+t+n)){for(int i=1;i<=t;i++)for(int j=1;j<=m;j++)scanf("%lf",&p[i][j]);memset(dp,0,sizeof(dp));for(int i=1;i<=t;i++)dp[i][0][0]=1;for(int k=1;k<=t;k++){for(int i=1;i<=m;i++){for(int j=0;j<=i;j++)dp[k][i][j]=dp[k][i-1][j]*(1.0-p[k][i])+(j-1<0?0:dp[k][i-1][j-1]*p[k][i]);}}double ans=1;for(int k=1;k<=t;k++)ans*=(1.0-dp[k][m][0]);//第k个人至少对一题 double res=1;for(int k=1;k<=t;k++){double cnt=0;for(int i=1;i<n;i++){cnt+=dp[k][m][i];}res*=cnt;}if(n==1)res=0;ans-=res;printf("%.3lf\n",ans);}return 0;}

Codeforces 540D Bad Luck Island

题意:a kill b  b kill c  c kill a 给出abc个数 问最后只剩下a的概率 a,b,c<=100

设dp[a][b][c] 表示三种种类为abc时 a获胜概率  按照每次选两个不同的种类来转移状态即可 .

也可以设dp[a][b][c]为还剩下abc时的概率,最后累加dp[i][j][0]即可

#include <bits/stdc++.h>using namespace std;typedef long long ll;typedef pair<ll,ll> ii;const int N=1e2+20;const ll inf=2e15;double f[N][N][N];int a,b,c;double DP(int a,int b,int c){if(a==0||(b==0&&c))return f[a][b][c]=0;if(f[a][b][c]!=-1)return f[a][b][c];if(c==0)return f[a][b][c]=1;double res=0,s=a+b+c,sum=a*(a-1)/2 + b*(b-1)/2+c*(c-1)/2;s=s*(s-1)/2.0;s-=sum;if(b&&c)res+=1.0*b*c/s*DP(a,b,c-1);if(a&&b)res+=1.0*a*b/s*DP(a,b-1,c);if(a&&c)res+=1.0*a*c/s*DP(a-1,b,c);return f[a][b][c]=res;}void init(){for(int i=0;i<=100;i++)for(int j=0;j<=100;j++)for(int k=0;k<=100;k++)f[i][j][k]=-1;}int main(){while(cin>>a>>b>>c){double x,y,z;init(); DP(a,b,c);x=f[a][b][c];init();DP(b,c,a);y=f[b][c][a];z=1-x-y;printf("%.12lf %.12lf %.12lf\n",x,y,z);}return 0;}

Codeforces 148D Bag of Mice

题意:w个白球,b个黑球,P,D两人轮流抽球,先抽到白球的人胜利,D抽球时,剩下的球会随机消失掉一个(剧情需要..),若游戏结束没人抽到白球则D获胜.
w,b<=1000 问P获胜的概率?

设DP[w][b]为球个数为wb时 P获胜的概率 s=w+b
w/s直接获胜,否则P抽到黑球后再转移到D抽到黑球后的状态(P要转移到下一个状态决策时,说明游戏还没结束,即P还没输)

#include <bits/stdc++.h>using namespace std;typedef long long ll;const ll mod=1e9+7;const int N=1e3+5;int a,b;double d[N][N];void init(){for(int i=0;i<N;i++)for(int j=0;j<N;j++)d[i][j]=-1;}double DP(int a,int b){//printf("%d %d\n",a,b);if(a==0)return d[a][b]=0;if(d[a][b]!=-1)return d[a][b];double res=0,s=a+b,num=1.0*b/s*(b-1)/(s-1);res+=1.0*a/s;if(b>=2)res+=1.0*num*a/(s-2)*DP(a-1,b-2);if(b>=3)res+=1.0*num*(b-2)/(s-2)*(DP(a,b-3));return d[a][b]=res;}int main(){while(cin>>a>>b){init();printf("%.9lf\n",DP(a,b));}return 0;}









原创粉丝点击