概率dp专辑
求概率
uva11021 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1962
给定n,k,m
有k个麻雀,每只活一天就会死,临死之前生出i只麻雀的概率为pi , 0<= i <n
问m天后,麻雀死光的概率
独立事件同时发生是每个事件的概率相乘, 每只麻雀都是独立的,只要求出一只麻雀m天后死亡的概率dp[m], 那么k只麻雀m天后死亡的概率为dp[m]^k
dp[i]表示i天后麻雀全部死亡的概率, 这个全部死亡即自己死亡,后代也死亡
dp[i]可以分解为n个子事件,生0->n-1个孩子,如果生j个孩子,那么j个孩子要在i-1天后死亡,这样全部的麻雀才会在i天后死亡,j个孩子要在i-1天后死亡是独立事件同时发生
所以是dp[i-1]^j,生j个孩子的概率为pj, 所以生j个孩子且i-1天后死亡也是独立事件,概率为pj * dp[i-1]^j
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/*
f[i] = p0
*/
const int N = + ;
double p[N],dp[N];
int main()
{
int n, k, m, t, tCase = ;
scanf("%d", &t);
while (tCase <= t)
{
scanf("%d%d%d", &n, &k, &m);
for (int i = ; i < n; ++i)
scanf("%lf", &p[i]);
dp[] = ;//0天后死亡是不可能的,所以概率是0
dp[] = p[];//一天后死亡的概率是不生孩子的概率
for (int i = ; i <= m; ++i)
{
dp[i] = ;
for (int j = ; j < n; ++j)
dp[i] += p[j] * pow(dp[i - ], j);
}
printf("Case #%d: %.7lf\n", tCase++, pow(dp[m], k));
}
return ;
}
http://acm.hit.edu.cn/hoj/problem/view?id=2866
给定n,m 表示第一个人的血量和第二个人的血量
然后接下来两行,每行6个数字,分别表示摇骰子得到点数1->6的概率
要我们求第一个人赢的概率
p1,p2,p 表示进行一次游戏,第一个人赢,第二个人赢,平局的概率
q1,q2表示前n局中,第一个人赢一局,其他都是平局, 第二个人赢一局,其他都是平局的概率,如图
q1 = p1/(1-p)
q2 = p2/(1-p)
dp[i][j] 表示第一个人赢i次,第二个人赢j次, dp[i][j] = dp[i-1][j]*q1 + dp[i][j-1]*q2
为什么是dp[i][j] = dp[i-1][j]*q1 + dp[i][j-1]*q2;
而不是 dp[i][j] = dp[i-1][j]*p1 + dp[i][j-1]*p2;
因为进行一局游戏,有第一个人赢,第二个人赢,平局
不可能理想到只进行了一次游戏,就可能第一个人赢 即dp[i-1][j]*p1,
所以要一个人赢一局,可能经过了n局,然后才赢一局, q1,q2就是经过了很多平局,才赢得一局的情况
答案是dp[hp2][0->hp1-1]
初始化条件是dp[0][0] = 1,这是必然的,因为刚开始的,必定两个人都没有赢过一次,所以是1,必定发生
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/* */
double dp[][];
int main()
{
int hp1, hp2;
double a[], b[];
int i, j;
double p1, p2, p, q1, q2;
while (scanf("%d%d", &hp1, &hp2) != EOF)
{
p1 = p2 = p = q1 = q2 = ;
for (i = ; i < ; ++i)
scanf("%lf", &a[i]);
for (i = ; i < ; ++i)
scanf("%lf", &b[i]);
for (i = ; i < ; ++i)
for (j = ; j < i; ++j)
{
p1 += a[i] * b[j];
p2 += a[j] * b[i];
}
p = 1.0 - p1 - p2;
p == ? q1 = q2 = : q1 = p1 / ( - p), q2 = p2 / ( - p);
//q1 = p1 / (1.0 - p);
//q2 = p2 / (1.0 - p);
memset(dp, , sizeof(dp));
dp[][] = 1.0;
for (i = ; i <= hp2; ++i)
{
for (j = ; j <= hp1; ++j)
{
if (j<hp1 && i) dp[i][j] += dp[i - ][j] * q1;
if (i<hp2 && j) dp[i][j] += dp[i][j - ] * q2;
}
}
double ans = ;
for (j = ; j < hp1; ++j)
ans += dp[hp2][j];
printf("%.6lf\n", ans);
}
return ;
}
poj 2151 http://poj.org/problem?id=2151
m t n
m到题目, t个队伍, n 冠军队最少解决n道题
t行,每行m个数字
表示每个队伍解决第i道题目的概率
问我们每个队伍至少解决一题,且冠军队至少解决n题的概率
p1为每个队伍至少解决一题的概率
p2为每个队伍解决k题的概率 1<=k<n
最终答案为p1-p2,每个队伍至少做出一题,且冠军队至少解决n题的概率
单独算出队伍至少解决k题的概率,每只队伍的概率相乘(独立事件同时发生)
dp[i][j][k] 为第i只队伍前j道题目解出k题的概率 dp[i][j][k] = dp[i][j-1][k-1] * p[i][j] + dp[j-1][k] *(1-p[i][j])
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/* */
double p[+][+];
double dp[ + ][ + ];
double s[];
int main()
{
int n, m, t, i, j, k;
while (scanf("%d%d%d", &m, &t, &n), m+n+t)
{
double p1, p2, tmp;
p1 = p2 = ;
for (i = ; i <= t; ++i)
{
tmp = ;
for (j = ; j <= m; ++j)
{
scanf("%lf", &p[i][j]);
tmp = tmp * ( - p[i][j]);//tmp为一题都没做出来的概率
}
p1 = p1*( - tmp);//p1为每个队伍至少做出一题的概率
}
for (i = ; i <= t; i++)
{
//dp[0][0] = 1;
memset(dp, , sizeof(dp));
dp[][] = ;
//for (j = 1; j <= m; ++j)
// dp[j][0] = dp[j - 1][0] * (1 - p[i][j]);
for (j = ; j <= m; ++j)
{
dp[j][] = dp[j - ][] * ( - p[i][j]);
for (k = ; k <=j; ++k)
{
dp[j][k] += dp[j - ][k] * ( - p[i][j]);
//if (k!=0)
dp[j][k] += dp[j - ][k - ] * p[i][j];
}
}
tmp = ;
for (k = ; k < n; ++k)
tmp += dp[m][k];
p2 = p2 * tmp;
}
printf("%.3f\n", p1 - p2);
}
return ;
}
poj3071 http://poj.org/problem?id=3071
给定一个n, 表示有2^n个队伍进行比赛
给定一个2^n * 2^n的矩形
pij 表示第i队伍打败第j只队伍的概率
比赛的规则是第一只队伍和第二只打,第三只队伍和第四只打,赢的晋级,然后还是依照这样的规则,如图
要我们求哪只队伍最终获胜的概率最大,输出该队伍
dp[i][j] 表示第i次比赛,队伍j获胜, 设k为要与j比赛的队伍 dp[i][j] += sum(dp[i-1][j] * dp[j-1][k] * p[j][k] )
那么怎么判断所要与j比赛的,我们对队伍进行分组, 队伍号/(i<<(i-1)) 就是组号了, 如果是组号是偶数,那么要与后一只队伍比赛,如果是奇数,那么要与前一只队伍比赛
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/* */
double dp[][], p[][];
int main()
{
int n, i, j, k;
while (scanf("%d", &n), n != -)
{
int m = << n;
for (i = ; i < m; ++i)
for (j = ; j < m; ++j)
scanf("%lf", &p[i][j]);
for (i = ; i < m; ++i)
dp[][i] = ;//dp[i][j]表示第i次比赛,获胜者是j的概率
for (i = ; i <= n; ++i)//2^n个队伍每次淘汰一半的队伍,所以要进行n次比赛才能决出胜负
{
int t = << (i-);
for (j = ; j < m; ++j)
{
dp[i][j] = ;
int teamNumWin = j / t;//分组
for (k = ; k < m; ++k)
{
int teamNumLose = k / t;//分组
if (teamNumWin % == && teamNumWin + == teamNumLose)//如果组数是偶数,那么与后一组比赛
dp[i][j] += dp[i - ][j] * dp[i - ][k] * p[j][k];
if (teamNumWin % == && teamNumWin - == teamNumLose)//如果组数是奇数,与前一组比赛
dp[i][j] += dp[i - ][j] * dp[i - ][k] * p[j][k];
}
} }
double Max = ;
int ans;
for (i = ; i < m; ++i)
if (dp[n][i]>Max)
{
Max = dp[n][i];
ans = i;
}
printf("%d\n", ans + );
}
return ;
}
http://codeforces.com/problemset/problem/148/D
给定w,b 分别为袋子里白老鼠和黑老鼠的数量
先取到白老鼠的人赢,一轮游戏后,即两个人各取了一只后,会从带子里随机逃出一只老鼠,老鼠逃出的概率是均等的。
问第一个人赢的概率
dp[i][j] 表示有i只白鼠,j只黑鼠的时候,第一个人赢的概率
这个人可能这一轮就赢,即取到白老鼠dp[i][j] += i/(i+j);
也可能下一轮才赢,那么这一轮可能的情况是:
第一个人取到黑,第二个人取到黑,逃掉一只黑的 dp[i][j] += j/(i+j)*(j-1)/(i+j-1)*(j-2)/(i+j-2)*dp[i][j-3];
第一个人取到黑,第二个人取到黑,逃掉一只白的 dp[i][j] += j/(i+j)*(j-1)/(i+j-1)*i/(i+j-2)*dp[i-1][j-2];
还有一种可能是
第一个人取到黑,第二个人取到白, 但这不是我们要考虑的,我们要考虑的是第一个人赢的概率
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/*
dp[i][j] 表示有i只白鼠,j只黑鼠的时候,princess赢的概率
dp[i][j] = i/(i+j) + j/(i+j) * (j-1)/(i+j-1) * (j-2)/(i+j-2) * dp[i][j-3] + j/(i+j) * (j-1)/(i+j-1)*i/(i+j-2)*dp[i-1][j-2]
*/
double dp[ + ][ + ];
int main()
{
int w, b, i, j;
scanf("%d%d", &w, &b);
for (i = ; i <= w; ++i)
dp[i][] = ;//如果只有白,没有黑,那么第一次抓就会赢
for (i = ; i <= w; ++i)
{
for (j = ; j <= b; ++j)
{
dp[i][j] += (double)i / (i + j);
if (j >= )
dp[i][j] += (double)j / (i + j) * (double)(j - ) / (i + j - ) * (double)(j - )/(i + j - )*dp[i][j - ];
if (j >= )
dp[i][j] += (double)j / (i + j) * (double)(j - ) / (i + j - ) * (double)i / (i + j - )*dp[i - ][j - ];
} }
printf("%.9lf\n", dp[w][b]);
return ;
}
poj http://poj.org/problem?id=3744
给定n, p 表示有n个地雷,p表示人走一步的概率,1-p表示人跳两步的概率, 人的其实位置在1
接下来n个数字表示n个地雷的位置, (地雷的位置不是递增的,坑爹啊)
我们求人安全走出雷区的概率
状态转移方程很简单dp[1] = 1 , 如果i不是雷区, dp[i] = dp[i-1] * p + dp[i-2] * (1-p), 如果i是雷区, dp[i]=0
但是雷区的长度实在是太长了,而这又是一个递推关系,所以我们可以用矩阵来优化
1--a[1]
a[1] + 1--a[2]
...进行分段
首先用矩阵快速幂求的dp[a[1]] ,dp[a[1]-1]
从而求的dp[a[1]+1] ,dp[a[1]],然后进行第二段矩阵快速幂,依次类推。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef long long LL;
const int INF = <<;
/* */
class Matrix
{
public :
double mat[][];
void makeZero()
{
for (int i = ; i < ; ++i)
for (int j = ; j < ; ++j)
mat[i][j] = ;
}
void makeUnit()
{
for (int i = ; i < ; ++i)
for (int j = ; j < ; ++j)
mat[i][j] = (i == j);
}
};
Matrix operator*(const Matrix &lhs, const Matrix &rhs)
{
Matrix ret;
ret.makeZero();
for (int k = ; k < ; ++k)
for (int i = ; i < ; ++i)
{
if (lhs.mat[i][k] == ) continue;
for (int j = ; j < ; ++j)
ret.mat[i][j] += lhs.mat[i][k] * rhs.mat[k][j];
}
return ret;
}
Matrix operator^(Matrix a, int n)
{
Matrix ret;
ret.makeUnit();
while (n)
{
if (n & )
ret = ret * a;
n >>= ;
a = a * a;
}
return ret;
}
int a[ + ];
int main()
{
int n, i, x;
double p;
int pre;
Matrix aa;
double f1, f2;
while (scanf("%d%lf", &n, &p) != EOF)
{
bool flag = false;
for (i = ; i <= n; ++i)
{
scanf("%d", &a[i]);
if (a[i] - a[i - ] == )
flag = true;
}
sort(a + , a + n + );
for (i = ; i <= n; ++i)
if (a[i] - a[i - ] == )
flag = true;
if (flag)
printf("%.7lf\n", );
else
{
pre = ;
f1 = ;
f2 = ;
for (i = ; i <= n; ++i)
{
aa.mat[][] = p;
aa.mat[][] = ;
aa.mat[][] = - p;
aa.mat[][] = ;
aa = aa ^ (a[i] - pre);
pre = a[i]+; //double tmpf2 = f2 * aa.mat[0][0] + f1*aa.mat[1][0];
//double tmpf1 = f2 * aa.mat[0][1] + f1*aa.mat[1][1];
//f2 = tmpf2;
//f1 = tmpf1;
//f2 = f1 * (1 - p);
//f1 = 0;
//这是根据上面的注释的代码推出来的
f2 = f2 * aa.mat[][] * ( - p);
}
printf("%.7f\n", f2);
}
}
return ;
}
uva10759 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1700
给定n个骰子和数字x,要我们求掷n个骰子,点数至少为x的概率
dp[i][j] 为前i个骰子,点数为j的概率 dp[i][j] += dp[i-1][j-k]/6 j-k>=0, 初始条件dp[0][0] = 1;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <math.h>
using namespace std;
#pragma warning(disable:4996)
typedef unsigned long long LL;
const int INF = <<;
/* */
struct node//因为要输出分数,所以建立一个数据结构,存分子和分母
{
LL x, y;//x/y
};
node dp[][];
LL gcd(LL a, LL b)
{
if (b == )
return a;
return gcd(b, a%b);
}
int main()
{
int n, x;
while (scanf("%d%d", &n, &x), n || x)
{
memset(dp, , sizeof(dp));
dp[][].x = dp[][].y = ;
int m = n * ;
for (int i = ; i <= n; ++i)
{
for (int j = i; j <= m; ++j)
{
for (int k = ; k <= ; ++k)
if (j - k >= && dp[i - ][j - k].y != )
{
if (dp[i][j].y == )
{
dp[i][j] = dp[i - ][j - k];
dp[i][j].y *= ;
continue;
}
LL y = dp[i - ][j - k].y * ;
LL g = gcd(dp[i][j].y, y);
LL tmp = dp[i][j].y / g * y;
dp[i][j].x = dp[i][j].x * (tmp / dp[i][j].y) + dp[i - ][j - k].x*(tmp / y);
dp[i][j].y = tmp;
//dp[i][j] += dp[i - 1][j - k] / 6;
}
}
} node ans = dp[n][x];
for (int i = x + ; i <= m; ++i)
{
if (dp[n][i].y == ) continue;
if (ans.y == )
{
ans = dp[n][i];
continue;
}
LL g = gcd(ans.y, dp[n][i].y);
LL tmp = ans.y / g * dp[n][i].y;
ans.x = ans.x *(tmp / ans.y) + dp[n][i].x*(tmp / dp[n][i].y);
ans.y = tmp;
}
LL g = gcd(ans.x, ans.y);
if (g != )
{
ans.x /= g;
ans.y /= g;
}
if (ans.y != )
{
if (ans.x%ans.y == )
printf("%llu\n", ans.x / ans.y);
else
printf("%llu/%llu\n", ans.x, ans.y);
}
else
printf("0\n");
}
return ;
}
下面的是求期望的
概率dp专辑的更多相关文章
- Codeforces 28C [概率DP]
/* 大连热身D题 题意: 有n个人,m个浴室每个浴室有ai个喷头,每个人等概率得选择一个浴室. 每个浴室的人都在喷头前边排队,而且每个浴室内保证大家都尽可能均匀得在喷头后边排队. 求所有浴室中最长队 ...
- HDU 4405 Aeroplane chess (概率DP)
题意:你从0开始,要跳到 n 这个位置,如果当前位置是一个飞行点,那么可以跳过去,要不然就只能掷骰子,问你要掷的次数数学期望,到达或者超过n. 析:概率DP,dp[i] 表示从 i 这个位置到达 n ...
- POJ 2096 Collecting Bugs (概率DP)
题意:给定 n 类bug,和 s 个子系统,每天可以找出一个bug,求找出 n 类型的bug,并且 s 个都至少有一个的期望是多少. 析:应该是一个很简单的概率DP,dp[i][j] 表示已经从 j ...
- POJ 2151 Check the difficulty of problems (概率DP)
题意:ACM比赛中,共M道题,T个队,pij表示第i队解出第j题的概率 ,求每队至少解出一题且冠军队至少解出N道题的概率. 析:概率DP,dp[i][j][k] 表示第 i 个队伍,前 j 个题,解出 ...
- 概率DP light oj 1030
t组数据 n块黄金 到这里就捡起来 出发点1 到n结束 点+位置>n 重掷一次 dp[i] 代表到这里的概率 dp[i]=(dp[i-1]+dp[i-2]... )/6 如果满6个的话 否则 ...
- hdu 4050 2011北京赛区网络赛K 概率dp ***
题目:给出1-n连续的方格,从0开始,每一个格子有4个状态,左右脚交替,向右跳,而且每一步的步长必须在给定的区间之内.当跳出n个格子或者没有格子可以跳的时候就结束了,求出游戏的期望步数 0:表示不能到 ...
- [转]概率DP总结 by kuangbin
概率类题目一直比较弱,准备把kuangbin大师傅总结的这篇题刷一下! 我把下面的代码换成了自己的代码! 原文地址:http://www.cnblogs.com/kuangbin/archive/20 ...
- SGU 422 Fast Typing(概率DP)
题目大意 某人在打字机上打一个字符串,给出了他打每个字符出错的概率 q[i]. 打一个字符需要单位1的时间,删除一个字符也需要单位1的时间.在任意时刻,他可以花 t 的时间检查整个打出来的字符串,并且 ...
- HDU 4050 wolf5x(动态规划-概率DP)
wolf5x Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...
随机推荐
- [ExtJS5学习笔记]第第二十四次 Extjs5形式上gridpanel或表单数据后台传输remoteFilter设定
本文地址:http://blog.csdn.net/sushengmiyan/article/details/39667533 官方文档:http://docs.sencha.com/extjs/5. ...
- Swift - 类初始化和反初始化方法(init与deinit)
1,init():类的初始化方法(构造方法) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ...
- CloseHandle(),TerminateThread(),ExitThread()的差别
线程的handle用处: 线程的handle是指向"线程的内核对象"的,而不是指向线程本身.每一个内核对象仅仅是内核分配的一个内存块,而且仅仅能由内核訪问.该内存块是一种数据结构, ...
- 多字符集(ANSI)和UNICODE及字符串处理方式准则
在我们编写程序的时候,使用最多的是字符串的处理,而ANSI和UNICODE的相互转换经常搞的我们头晕眼乱. 应该说UNICODE是一种比较好的编码方式,在我们的程序中应该尽量使用UNICODE编码方式 ...
- WinDBG 技巧:如何生成Dump 文件(.dump 命令)
程序崩溃(crash)的时候, 为了以后能够调试分析问题, 可以使用WinDBG要把当时程序内存空间数据都保存下来,生成的文件称为dump 文件. 步骤: 1) 打开WinDBG并将之Attach 到 ...
- cape town
开普敦_百度百科 开普敦
- LeetCode——Populating Next Right Pointers in Each Node II
Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...
- codeforces 577
codeforces 577A 题目链接:http://codeforces.com/problemset/problem/577/A 题目大意:给出一个n*n的表格,每个表格对应的值为横坐标*纵坐标 ...
- JNI生成so
软件:android-ndk-r8 推荐使用这个版本,可以直接不用安装Cygwin软件就可以编译. 然后在系统环境变量中path选项中添加安装路径,比如我的:C:\android-ndk-r8: 然后 ...
- Hbase0.96源码之HMaster(一)
从main()函数開始 public static void main(String [] args) { VersionInfo.logVersion(); new HMasterCommandLi ...