标签:style blog http color io os ar java for
一 概率问题的论文
二 入门题目
1、POJ 3744 Scout YYF I (简单题)
题意:一条路上有n个地雷 ,a[i]代表第i个地雷放的位置,求安全走过这段路的概率
分析:若第k个位置有地雷则安全走过这个位置的方案为在第k-1个位置跳两步概率为(1-p)
从反面考虑 已经安全走过了第i-1个雷 则在第i个雷的死掉的概率为 1-p(从走到a[i-1]走到a[i]) P=p*ans[i-1]+(1-p)*ans[i-2]
ans[i]代表走到i位置的概率,由于n比较大 需要用矩阵进行优化
解题报告:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int a[20]; struct matrix { double m[2][2]; }; matrix I={1.0,0,0,1.0}; matrix multi(matrix A,matrix B) { matrix C; for(int i=0;i<2;i++){ for(int j=0;j<2;j++){ C.m[i][j]=0; for(int k=0;k<2;k++) C.m[i][j]+=A.m[i][k]*B.m[k][j]; } } return C; } double pow(int k,matrix A) { matrix ans = I,p=A; while(k){ if(k&1){ ans=multi(ans,p); k--; } k>>=1; p=multi(p,p); } return ans.m[0][0]; } int main() { int n; double p; while(cin>>n>>p){ for(int i=1;i<=n;i++) cin>>a[i]; a[0]=0; sort(a,a+n+1); matrix A={p,1.0-p,1.0,0}; double ans=1; for(int i=0;i<n;i++){ ans*=(1-pow(a[i+1]-a[i]-1,A)); } printf("%.7lf\n",ans); } return 0; }
4、POJ 2151 Check the difficulty of problems (简单题)
算很常见的一种dp表示吧。 学会 “至少” 这类问题角度的转化。
解题报告
5、ZOJ 3380 Patchouli‘s Spell Cards (中等题)
有m个位置,每个位置填入1~n中的一个数,求至少有L个数一样的概率。 dp转移还行,就是要用Java的 高精度 解题报告
6、SGU 495 Kids and Prizes (YY题)
YY题,O(1)推出结论,想不到就觉得比较难, 分析问题的角度值得学习。
解题报告
7、POJ 2096 Collecting Bugs (简单题)
题意:一个人一天只能找出一个bug来 一个公司有s个子公司 ,有n种bug,让这个人去找,求找出所有的n种bug而且每个公司都要找出bug所需要的时间的期望
分析:dp求期望入门题。关键要体会为什么要倒着推过来
dp[i][j]表示在i个公司中一共找到了j种bug
注:E(aA+bB+cC+.....n*N)=a*E(A)+b*E(B)+.......+n*E(N);
状态转移方程很好理解
dp[i][j]=(dp[i+1][j]*p1+dp[i][j+1]*p2+dp[i+1][j+1]+1)/(1-p4);
p1=(s-i)*j/n/s;
p2=i*(n-j)/n/s;
p3=(s-i)*(n-j)/n/s;
p4=i*j/n/s;
解题报告
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn = 1010; double dp[maxn][maxn]; int main() { int n,s; while(~scanf("%d%d",&n,&s)){ dp[s][n]=0; for(int i=s;i>=0;i--){ for(int j=n;j>=0;j--){ if(i==s&&j==n) continue; dp[i][j]=(dp[i+1][j]*(s-i)*j*1.0/(s*n*1.0)+dp[i+1][j+1]*(s-i)*(n-j)*1.0/(s*n*1.0)+dp[i][j+1]*i*(n-j)*1.0/(s*n*1.0)+1.0)/(1.0-i*j*1.0/n/s); } } printf("%.4lf\n",dp[0][0]); } return 0; }
题意:一个r*c的地图 一个人在(1,1)每次可以留在原地 或者消耗两个体力向左走一格或则向下走一格,求走到(r,c)所消耗的体力的期望
分析:dp[i][j]表示从(i,j)走到终点所消耗体力的期望
dp[i][j]=(dp[i+1][j]*p1+dp[i][j+1]*p2+2)/(1-p3)
p1为向右走的概率 ,p2为向下走的概率 ,p3为原地不动的概率
注:E(aA+bB+cC+.....n*N)=a*E(A)+b*E(B)+.......+n*E(N); 包含状态A,B,C的期望可以分解子期望求解
解题报告
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> using namespace std; const int maxn = 1002; double map[maxn][maxn][3]; double dp[maxn][maxn]; int main() { int r,c; while(~scanf("%d%d",&r,&c)){ for(int i=1;i<=r;i++) for(int j=1;j<=c;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=r;i>=1;i--){ for(int j=c;j>=1;j--){ if(i==r&&j==c) continue; if(map[i][j][0]==1.00) continue; dp[i][j]=(map[i][j][1]*dp[i][j+1]+map[i][j][2]*dp[i+1][j]+2)/(1-map[i][j][0]); } } printf("%.3lf\n",dp[1][1]); } return 0; }
分析:dp[i]=1/6(dp[i+1]+....+dp[i+6]+1) 如果i可以直接到k的话 则dp[i]=dp[k]; dp[i]表示从i到终点所要扔的色子次数的期望
解题报告
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn = 100007; double dp[maxn]; int f[1010][2]; int main() { int n,m; while(~scanf("%d%d",&n,&m)){ if(n==0&&m==0) break; for(int i=0;i<m;i++) scanf("%d%d",&f[i][0],&f[i][1]); memset(dp,0,sizeof(dp)); double p = 1.0/6; for(int i=n;i>=0;i--){ if(i>=n) continue; dp[i]=(dp[i+1]+dp[i+2]+dp[i+3]+dp[i+4]+dp[i+5]+dp[i+6])*p+1; for(int j=0;j<m;j++){ if(i==f[j][0]){ dp[i]=dp[f[j][1]]; break; } } } printf("%.4lf\n",dp[0]); } return 0; }
#include<cstdio> #include<cstring> #include<cmath> #define max(a,b) a>b?a:b const int LMT=20003; const double is=0.5*(1+sqrt(5)); double dp[LMT]; int have[102]; int main() { int i,n,f,j,all; while(~scanf("%d%d",&n,&f)) { memset(dp,0,sizeof(dp)); all=-1; for(i=0;i<n;i++) { scanf("%d",&have[i]); all=max(all,have[i]); } all<<=1; for(i=max(all,f);i>=f;i--) { for(j=0;j<n;j++) if(i>have[j])dp[i]+=(int)(is*have[j]*have[j]); else dp[i]+=1+dp[i+have[j]]; dp[i]/=n; } printf("%.3lf\n",dp[f]); } return 0; }
题意:给定一个r*c的棋盘 每一步可以放一个棋子 求多少步可以使每行每列都有棋子的期望
分析:这题是2014年 2014 ACM-ICPC Asia Mudanjiang Regional 的题目,其实只要做过 概率dp的题目就很好写的
dp[i][j][k]表示一共用了i个棋子 使i行k列有了棋子
dp[i][j][k]=(dp[i+1][j][k]*p1+dp[i+1][j+1][k]*p2+dp[i+1][j][k+1]*p3+dp[i+1][j+1][k+1]*p4)
p1=(j*k-i)/(r*c-i);
p2= (r-j)*k/(r*c-i);
p3=(c-k)*j/(r*c-i);
p4=(r-j)*(c-k)*(r*c-i);
解题报告:
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxn = 51; double dp[maxn*maxn][maxn][maxn]; int main() { int r,c,t; scanf("%d",&t); while(t--){ scanf("%d%d",&r,&c); memset(dp,0,sizeof(dp)); for(int i=r*c-1;i>=0;i--){ for(int j=r;j>=0;j--){ for(int k=c;k>=0;k--){ if(j==r&&k==c) continue;//判断分母是不是为0 if(j*k<i) continue;//判断分子是不是负数 double p1=1.0*(j*k-i)/(r*c-i); double p2=1.0*(r-j)*k/(r*c-i); double p3=1.0*(c-k)*j/(r*c-i); double p4=1.0*(r-j)*(c-k)/(r*c-i); // cout<<"p1 "<<p1<<endl; // cout<<"p2 "<<p2<<endl; //cout<<"p3 "<<p3<<endl; //cout<<"p4 "<<p4<<endl; dp[i][j][k] =dp[i+1][j][k]*p1+dp[i+1][j+1][k]*p2+dp[i+1][j][k+1]*p3+dp[i+1][j+1][k+1]*p4+1.0; } } } printf("%.8lf\n",dp[0][0][0]); } return 0; }
12、HDU 4336 Card Collector (简单题)
状态压缩概率DP。或者用容斥原理直接求。
题意:有n种卡片,每买一包零食则可能得到其中的一种也可能得不到,得到第i种卡片的概率为pi求,收集齐所有的卡片需要的买零食的期望
由于n比较小我们可以进行状态压缩
dp[i] 化成二进制1的位置代表收集了 这几种所需要买的零食的期望
eg: dp[(1101)2] =(dp[(1100)2]*p1+dp[(1001)2]*p3+dp[(0101)2]*p4+1)/(1-p3-p(零食里没有卡片))
解题报告
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 1<<20; double dp[maxn+1]; double p[25]; int main() { int n; while(~scanf("%d",&n)){ p[0]=1; for(int i=1;i<=n;i++){ scanf("%lf",p+i); p[0]-=p[i]; } dp[0]=0; double x; for(int i=1;i<(1<<n);i++){ x=p[0]; dp[i]=1; for(int j=0;j<n;j++){ if((1<<j)&i) dp[i]+=p[j+1]*(dp[i-(1<<j)]); else x+=p[j+1]; } dp[i]/=(1-x); } printf("%.4lf\n",dp[(1<<n)-1]); } return 0; }
13、ZOJ 3329 One Person Game (中等题-)
骰子求期望的题, 递推公式有点麻烦。
解题报告
2011年北京现场赛的题目, 用求期望的方法 求概率的题,公式有一点点繁琐,仔细想也是可以做出来的 、
解题报告
高斯消元,这题是学长出的,目的是坑人题意的, 题意理解以后就是很裸的高斯消元(用程序解方程),但还是有很多坑
只做了一部分题目,剩下的以后做了会继续更新。。。
标签:style blog http color io os ar java for
原文地址:http://blog.csdn.net/bigbigship/article/details/40118029