您的位置:首页 > 其它

概率DP【入门】

2011-10-25 21:45 483 查看

HDU 3076 ssworld VS DDD

题意: 2个人分别有AB的血数,轮流扔骰子,数小的自减一血,平的不变,谁先到减0, 谁输,问A赢的概率。
题解: 考虑平局的出现对局面没有影响,因此把平局规约到非平局里即可,对于每一次p1表示A赢,p2表示B赢,p=1-p1-p2表示平局,A赢的概率为p1+p*p1+p^2*p1+…p^n*p1,n->无穷,即a=q1/(1-p);b=q2/(1-p);
然后在他们一定会分出胜负的情况下就可以dp了:

dp[i][j]=dp[i][j-1]*a+dp[i-1][j]*b;

代码很丑,数组开的太大还MLE一次

#include <cstdio>
#include <cstring>

const int maxn=2000+5;
double sum[2][7];
double p[2][7] , dp[maxn][maxn];

int A,B;
double a,b;//算上平局的单次
double a1,b1;//单次

void DP()
{
memset (dp, 0, sizeof(dp));
a=b=a1=b1=0.0;
for (int i=1 ; i<6 ; ++i)
{
a1+=sum[1][i]*p[0][i+1];
b1+=sum[0][i]*p[1][i+1];
}
//printf("a==%lf , b==%lf\n", a1, b1);
double p=1-a1-b1;
a=a1/(1.0-p);
b=b1/(1.0-p);
//printf("%lf , %lf  , 平局%lf\n", a, b, p);
dp[0][0]=1;

for (int i=0 ; i<=A ; ++i)
{
for (int j=0 ; j<=B ; ++j)
{
if(i>0 && j<B)dp[i][j]+=dp[i-1][j]*a;
if(j>0 && i<A)dp[i][j]+=dp[i][j-1]*b;
}
//printf("\n");
}

double ans=0;
for (int i=0 ; i<B ; ++i)
{
ans+=dp[A][i];
}
printf("%lf\n",ans);
}

/*
5 5
0.500 0.500 0.000 0.000 0.000 0.000
0.000 0.000 0.000 0.000 0.000 1.000
5 5
0.000 0.000 0.000 0.000 0.900 0.100
0.000 0.000 0.000 0.000 0.900 0.100
*/

int main ()
{
while (~scanf("%d%d",&A,&B))
{
sum[0][0]=sum[1][0]=0;
for (int i=1 ; i<=6 ; ++i)
{
scanf("%lf", p[0]+i);
sum[0][i]=sum[0][i-1]+p[0][i];
}
for (int i=1 ; i<=6 ; ++i)
{
scanf("%lf", p[1]+i);
sum[1][i]=sum[1][i-1]+p[1][i];
}
DP();
}

return 0;
}
【------------------------------------------------------】

poj 2151 Check the difficulty of problems

m道题,t个队伍,n个最少题数,给出t*m的概率,表示队伍做出题的概率。求所有队伍都至少出1题,且至少有一个队伍出n道题以上概率。

#include <cstdio>
#include <cstring>

double dp[35][35];
double sum[3];

int main ()
{
int m,t,n;
double p;
while (~scanf("%d%d%d", &m, &t, &n) , (m||n||t))
{
double ans=1.0,ans2=1.0;
for (int i=0 ; i<t ; ++i)
{
dp[0][0]=1;
for (int j=1 ; j<=m ; ++j)
{
scanf("%lf", &p);
for (int k=0 ; k<=j  && k<=m ; ++k)
dp[k][j]=dp[k][j-1]*(1-p)+(k?dp[k-1][j-1]*p:0);
}

sum[0]=dp[0][m];
sum[1]=0.0;
for (int j=1 ; j<n ; ++j)sum[1]+=dp[j][m];
ans*=(1-sum[0]);
ans2*=sum[1];
}
printf("%.3lf\n",ans-ans2);
}
return 0;
}


【---------------------------------------------------】

HDU 3853 (2011夏)北邮邀请赛 i题

错误代码:

正向推的公式是错的, 原因是用错了无穷级数。

#include <cstdio>
#include <cstring>

const int maxn=1000+12;
const double inf=20000000.0;
using namespace std;

double map[maxn][maxn][3], dp[maxn][maxn];
///dp[i][j]=(dp[i-1][j]+1)*map[i-1][j][2]+(dp[i][j-1]+1)*map[i][j-1]+(dp[i][j]+1)*map[i][j]
int n, m;
double tmp;
int main ( )
{
while (~scanf("%d%d", &n, &m))
{
dp[1][1]=0.;
for (int i=1 ; i<=n ; ++i)
{
for (int j=1 ; j<=m ; ++j)
{
tmp=0.0;
scanf("%lf%lf%lf", map[i][j]+0, map[i][j]+1, map[i][j]+2);
if(map[i][j][0]!=1.0)
{
if(i)tmp+=(dp[i-1][j]+1)*map[i-1][j][2];
if(j)tmp+=(dp[i][j-1]+1)*map[i][j-1][1];
tmp+=map[i][j][0];
tmp/=(1-map[i][j][0]);
}
else tmp=0.;
dp[i][j]=tmp;
///printf("%d %d %lf\n", i, j, dp[i][j]);
}
}
dp
[m]=map[n-1][m][2]*(dp[n-1][m]+1)+map
[m-1][1]*(dp
[m-1]+1);
printf("%.3lf\n", dp
[m]*2);
}
return 0;
}
/*
2 2
0.00 0.50 0.50    0.50 0.00 0.50
0.50 0.50 0.00    1.00 0.00 0.00
3 2
0.00 0.50 0.50    0.50 0.00 0.50
0.00 0.50 0.50    0.50 0.00 0.50
0.50 0.50 0.00    1.00 0.00 0.00
*/


改成向前推就好了。

在2维状态下递推期望 , 利用期望的公式,

E = x1 * p1 + x2 * p2 + …… xn*pn。

状态转移方程式:

f[i][j] =(f[i][j]+2)* exp[i][j][1] + (f[i+1][j]+2) * exp[i][j][2] + (f[i][j+1]+2) * exp[i][j][3]

这个式子左右都有f[i][j],化简后:

f[i][j] =((f[i+1][j]+2) * exp[i][j][2] + (f[i][j+1]+2) * exp[i][j][3]+ 2 * exp[i][j][1])/ (1 - exp[i][j][1])

#include <cstdio>
#include <cstring>

const int maxn=1000+12;
using namespace std;

double map[maxn][maxn][3], dp[maxn][maxn];
double tmp;
int main ()
{
while (~scanf("%d%d", &n, &m))
{
for (int i=1 ; i<=n ; ++i)
{
for (int j=1 ; j<=m ; ++j)
{
scanf("%lf%lf%lf", map[i][j]+0, map[i][j]+1, map[i][j]+2);
}
}
memset (dp, 0, sizeof(dp));
for (int i=n ; i>0 ; --i)
{
for (int j=m ; j>0 ; --j)
{
if(i==n && j==m)continue;
if(map[i][j][0]!=1.)
{
tmp=1+dp[i][j+1]*map[i][j][1]+dp[i+1][j]*map[i][j][2];
tmp/=(1-map[i][j][0]);
}
dp[i][j]=tmp;
}
}
printf("%.3lf\n", dp[1][1]*2);
}
return 0;
}


之后要刷的题:

HDU 4050 /// bupt 现场赛 I题 POJ3071 1202
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: