UVa 10207 (组合数的高精度计算)
来源:互联网 发布:阿里云服务器华东2 编辑:程序博客网 时间:2024/06/04 18:29
problem
In this particular problem, TheUnreal Tournamentis a tournament, which consists of only two teams. Letthese two teams beAbahoniandMohamedan. They play in between them notmore than 2n− 1 games, the winnerbeing the first team to achievenvictories.You can assume that there are no tied games, the result of each game isindependent and for any match there is a constant probabilitypthat teamAbahoni will win and hence there is a constant probabilityq= 1 −pthat team Mohamedan willwin.
P(i,j) is the probability that teamAbahoniwill win the series given that they still needimore victories to achieve this,whereas teamMohamedanstill needjmore victories if they are to win. TheP(i,j)can be computed with a function like the following
Function P(i,j)
if i = 0 then return 1 else if j = 0 then return 0 elsereturn pP(i-1,j) + qP(i,j-1)
You will haveto write a program that gives the probability of winning for anyp,iandjand also gives the numberof recursive calls required if the function above is used to get theprobabilityP(i,j).
Input
The input filecontains several sets of input. The first line of a set contains onefloating-point numberp(0< p <1), and an integerN(0 ≤ N < 1001) wherep isthe winning probability ofAbahoniandN is the number queries to follow.Each of the nextNlines contains twointegersi(0 ≤i ≤ 1000) and j(0 ≤j≤ 1000). Input is terminated by a set,which has zero as the value ofN.This set should not be processed.
Output
For each query you should printtwo lines. The first line contains the value ofP(i,j) with five digitsafter the decimal and the second line contains a round number which is thenumber of recursive calls needed if the function mentioned above was used to determinethe value ofP(i,j). If the value ofP(i,j) is undefined you should print ‘-1’ as its value with similarformatting. A blank line should be printed between the outputs of twoconsecutive sets.
Sample Input
0.5 3
1 1
2 2
3 3
0.5 2 10 3
10 2
0.7 0
Sample Output
0.50000
2
0.50000
10
0.50000
38
0.01929
570
0.00586
130
传送门:点击打开链接
思路
题目大致意思是:Aba和Moh要进行若干场比赛,每场比赛Aba获胜的概率是p,Moh获胜的概率是q,其中p和q为正实数,且p+q=1。
若Aba率先获胜i场比赛,则Aba就能获得最终的胜利,否则若Moh率先获胜j场比赛,则Moh获得最终胜利。
题目给出二元函数P(i,j)计算Aba的胜率:
Function P(i,j)if i=0 then return 1else if j=0 then return 0else return p*P(i-1,j)+q*P(i,j-1);EndFunction求解P(i,j)以及递归求解P(i,j)时调用到上述函数的次数
数据范围:至多1000组数据,每组数据中 i,j<=1000
直接按定义模拟求解需要O(n^2)的复杂度,观察解的形式,看能否降低复杂度,如下图:
最左列1.0表示P(0,k)的值(此时已经不需要进行游戏,Aba胜利,胜率1.0),最底下一列的0.0表示P(l,0)的值(Aba战败,胜率0.0)。而对最终答案P(i,j)的每一份概率贡献对应了从左列某个节点(0,k)出发向右或向上到达(i,j)的路径(第一步必须向右)。向右走,则路径的概率应乘上系数p;向上走,则乘上系数q。
理解:假如现在比赛进行到上图(i,j)点所示阶段,那么下一步有两种选择:Aba胜利,概率为p,向左走;Aba战败,概率为q,向右走。可以看出,到达最左边一列即为Aba胜利的标志。
于是从末状态(在最左边一列上)进行思考,从某个最左列起点(0,k)先向右一步到达(1,k),再到达(i,j)的方法数为C(i-1+j-k,i-1),则从(0,k)出发到达(i,j),概率和为C(i-1+j-k,i-1)* p^i * q^j-k。即为:
于是可以只是用O(N)的时间计算P(i,j)。
再考虑递归求解P(i,j)遍历的节点数,设为F(i,j)。通过归纳,得到:
F(0,j)=F(i,0)=0 (递归终止条件,自然为0)
F(i,j)=F(i-1,j)+F(i,j-1)+2
做等量代换,令G(i,j)=F(i,j)+2
有G(i,j)=G(i-1,j)+G(i,j-1)
观察到这个递推式与组合数类似:
考虑通过构造,将G(i,j)与C(n,r)联系起来。令n=i+j且r=i,则G(i,j)=C*C(i+j,i)。其中C为常数,带入初值可得C=2。
所以G(i,j)=2*C(i+j,i),F(i,j)=2*C(i+j,i)-2
代码示例
(过样例,由于本版本高精度问题?未AC,如有改进方法,还请留言,谢谢!另外如果是极限数据,好像会TLE)
//#define LOCAL#include<iostream>#include<algorithm>#include<cstdio>#include<stdlib.h>#include<string>#include<string.h>#include<math.h>using namespace std;//辅助比较函数int compare(string str1,string str2){ if(str1.length()>str2.length()) return 1; else if(str1.length()<str2.length()) return -1; else return str1.compare(str2);}//高精度加法//只能是两个正数相加string add(string str1,string str2){ string str; int len1=str1.length(); int len2=str2.length(); if(len1<len2){ for(int i=1;i<=len2-len1;i++) str1="0"+str1; } else{ for(int i=1;i<=len1-len2;i++) str2="0"+str2; } len1=str1.length(); int cf=0; int temp; for(int i=len1-1;i>=0;i--){ temp=str1[i]-'0'+str2[i]-'0'+cf; cf=temp/10; temp%=10; str=char(temp+'0')+str; } if(cf) str=char(cf+'0')+str; return str;}//高精度减法//只能是两个正数相减,而且是大减小string sub(string str1,string str2){ string str; int tmp=str1.length()-str2.length(); int cf=0; for(int i=str2.length()-1;i>=0;i--){ if(str1[tmp+i]<str2[i]+cf){ str=char(str1[tmp+i]-str2[i]-cf+'0'+10)+str; cf=1; } else{ str=char(str1[tmp+i]-str2[i]-cf+'0')+str; cf=0; } } for(int i=tmp-1;i>=0;i--){ if(str1[i]-cf>='0'){ str=char(str1[i]-cf)+str; cf=0; } else{ str=char(str1[i]-cf+10)+str; cf=1; } } str.erase(0,str.find_first_not_of('0')); return str;}//高精度乘法//只能是两个正数相乘string mul(string str1,string str2){ string str; int len1=str1.length(); int len2=str2.length(); string tempstr; for(int i=len2-1;i>=0;i--){ tempstr=""; int temp=str2[i]-'0'; int t=0; int cf=0; if(temp!=0){ for(int j=1;j<=len2-1-i;j++) tempstr+="0"; for(int j=len1-1;j>=0;j--){ t=(temp*(str1[j]-'0')+cf)%10; cf=(temp*(str1[j]-'0')+cf)/10; tempstr=char(t+'0')+tempstr; } if(cf!=0) tempstr=char(cf+'0')+tempstr; } str=add(str,tempstr); } str.erase(0,str.find_first_not_of('0')); return str;}//高精度除法//两个正数相除,商为quotient,余数为residue//需要高精度减法和乘法void div(string str1,string str2,string "ient,string &residue){ quotient=residue=""; if(str2=="0"){ quotient=residue="ERROR"; return ; } if(str1=="0"){ quotient=residue="0"; return ; } int res=compare(str1,str2); if(res<0){ quotient="0"; residue=str1; return ; } else if(res==0){ quotient="1"; residue="0"; } else{ int len1=str1.length(); int len2=str2.length(); string tempstr; tempstr.append(str1,0,len2-1); for(int i=len2-1;i<len1;++i){ tempstr=tempstr+str1[i]; tempstr.erase(0,tempstr.find_first_not_of('0')); if(tempstr.empty()) tempstr="0"; for(char ch='9';ch>='0';ch--){ string str,tmp; str=str+ch; tmp=mul(str2,str); if(compare(tmp,tempstr)<=0)//试商成功 { quotient=quotient+ch; tempstr=sub(tempstr,tmp); break; } } } residue=tempstr; } quotient.erase(0,quotient.find_first_not_of('0')); if(quotient.empty()) quotient="0";}string c[2001][2001];//组合数void init(){ for(int i=1;i<=400;i++) for(int j=1;j<=400;++j) c[i][j]="0"; c[0][0]="1"; c[1][0]=c[1][1]="1"; for(int i=2;i<=400;++i){ for(int j=0;j<=i;++j){ if(j==0||j==i) c[i][j]="1"; else c[i][j]=add(c[i][j],add(c[i-1][j],c[i-1][j-1])); } }}int main(){ #ifdef LOCAL freopen("read.txt","r",stdin); #endif // LOCAL init();//构造组合数 double p,q,ans; int query; int m,n; while(cin>>p>>query&&query) { q=1-p; while(query--) { cin>>m>>n; ans=0; if(m==0){ if(n==0) ans=-1; else ans=1; } else{ for(int k=1;k<=n;++k){ ans+=atof(c[m-1+n-k][m-1].c_str())*pow(p,m)*pow(q,n-k); } } printf("%.5lf\n",ans);//概率计算完成 //下面计算次数 if(m==0||n==0) cout<<0<<endl; else cout<<sub(mul(c[m+n][m],"2"),"2")<<endl; } cout<<endl; } return 0;}
- UVa 10207 (组合数的高精度计算)
- Knuth的计算组合数的较高精度算法
- 组合数的计算
- 组合数的计算
- 组合数的计算
- BZOJ1005 明明的烦恼 (prufer序列 组合数 高精度)
- 计算组合数的算法
- 黄金分割数高精度计算
- SDUTOJ-1574 组合数的计算(简单数论)
- [BZOJ3907]网格(卡特兰数+组合数学+高精度)
- bzoj 3907: 网格 (卡特兰数+组合数学+高精度)
- UVA 465 Overflow 高精度加法乘法(误!。其实应该说是浮点数的优势。。。)
- 组合数计算问题的总结
- [Java] 计算组合数的代码
- 组合数C(n,m)的计算
- 2种计算组合数的方法
- 计算组合数的几种方法
- uva 11027 - Palindromic Permutation(组合数)
- mysql触发器(trigger)
- 谈谈 ES6 的 Promise 对象
- 说在前面
- 网页跳转实现的多种方式
- 注释转换(C --> C++)
- UVa 10207 (组合数的高精度计算)
- JavaScript之兼容性事件的绑定和解除
- 前端技术浏览器对象模型篇
- 如何获取input框type=file选中的文件对象(FileReader)
- 线程同步
- POJ 2387 经典解法,优先队列的dijkstra+链式前向星存储
- 链表的合并(先排序在合并)
- [paper] Simple Does It
- 略谈OpenGL中的共享上下文(EGL Context)