随机图 概率+组合数学
2017-11-01 21:13
387 查看
【问题描述】
随机生成一张n个点的无向图。把它的顶点标号为1~n。
对于一个点对i,j(1 <= i < j <= n),有千分之p的概率成为这张图中的一条边(i,j)。不同的边出现的概率是相互独立的。
求产生一个至少含有一个大于等于4的连通块的图的概率是多少。
【输入格式】
一行两个整数n,p,表示图的点数和边在图上的概率。
【输出格式】
输出一行一个实数,表示所求的概率。结果保留4位小数。
【输入样例】
6 100
【输出样例】
0.1184
【样例解释】
时间限制:1秒 内存限制:128M
【数据范围】
4<=n<=100
——————————————————————————————————————————————————————
实际上好像有直接dp的做法,这里我就直接给出我自己的做法了(感觉加深了对组合数学的理解?雾)。
用补集的思想。P(图中至少包含一个以上的4个点的连通分量)= 1-P(图中连通分量大小最大的分量大小不超过3)
可以考虑枚举图中三种连通分量的个数(设为n1,n2,n3)
设g(n1,n2,n3)为图中含有n1个大小为1的连通分量(x1),n2个……(x2),n3个……(x3)的概率。
则ans = 1-sum{ g(n1,n2,n3) | n1+n2 * 2+n3 * 3=N }
P=P/1000
有C(N,n1)种方法选出n1所在的位置,然后有C(N-n1,n2*2)种方法选出n2所在的位置,最后n3的位置就是确定的了。
所以对于确定的n1,n2,n3,一共有C(N,n1) * C(N-n1,n2*2)种选法选出三种连通分量各自所在的位置。
这些方法都是独立的,相加,但是三个分量的形成是同时发生的,所以三种分量各自在对应大小的区间形成的概率应该相乘。
关键问题:怎么计算在给定数量的位置中全都形成大小为1/2/3的连通分量的概率。
图中有n个点的时候:
某一个点自己形成一个大小为1的连通分量x1的概率P1(n)=(1-P)^(n-1)(跟这个点有关的边有n-1条,所有的都没有出现)
某两个点一起形成一个大小为2的连通分量x2的概率P2(n)=P*(1-P)^(2n-4)(跟这两个点有关的边有2N-3条,其中只有连接这两个点的出现了,其他的都没出现)
某三个点一起形成一个大小为3的连通分量x3的概率P3(n)=3 * P * P * (1-P)^(3n-8)+P * P * P * (1-P)^(3n-9)
(跟这三个点有关的边有3N-6条,可能只需要两条边三个点就连在一起了,这个时候出现2条,三种方式,有3N-8条没有出现;还有可能有三条边把这三个点连接在一起)
但是假如现在有k个点,要计算这k个点全部都是大小为1的连通分量的概率的话P1^k这个答案是不正确的,重复计算了每一条边的概率贡献。
应该递归计算。
设f1(k)表示在k个点中只存在x1的概率,f1(k)=C(k-1,0) * P1(k) * f1(k-1)
设f2(k)表示在k个点中只存在x2的概率,f2(k)=C(k-1,1) * P2(k) * f2(k-2)
设f3(k)表示在k个点中只存在x3的概率,f3(k)=C(k-1,2) * P3(k) * f3(k-3)
这样递归计算的话每条边对概率的贡献就不会重复计算了。
对于每一种n1,n2,n3,内部是独立的可以用递推来计算,但是这三个板块之间的边的概率还没有考虑到(当然全部都没有出现)。
一共有n1 * (n2 * 2+n3 * 3)+n2 * n3 * 6条跨越板块的边没有出现,这种情况的概率P4=(1-P)^(n1 * (n2 * 2+n3 * 3)+n2 * n3 * 6)
所以说对于一种n1,n2,n3的方案的概率就出来了:
g(n1,n2,n3)=C(N,n1) * C(N-n1,n2 * 2) * P4 * f1(n1) * f2(n2 * 2) * f3(n3 * 3)
然而组合数太大了,方便起见直接取了阶乘的自然对数来算,最后算答案的时候乘方算回来就可以了。
AC代码:
随机生成一张n个点的无向图。把它的顶点标号为1~n。
对于一个点对i,j(1 <= i < j <= n),有千分之p的概率成为这张图中的一条边(i,j)。不同的边出现的概率是相互独立的。
求产生一个至少含有一个大于等于4的连通块的图的概率是多少。
【输入格式】
一行两个整数n,p,表示图的点数和边在图上的概率。
【输出格式】
输出一行一个实数,表示所求的概率。结果保留4位小数。
【输入样例】
6 100
【输出样例】
0.1184
【样例解释】
时间限制:1秒 内存限制:128M
【数据范围】
4<=n<=100
——————————————————————————————————————————————————————
实际上好像有直接dp的做法,这里我就直接给出我自己的做法了(感觉加深了对组合数学的理解?雾)。
用补集的思想。P(图中至少包含一个以上的4个点的连通分量)= 1-P(图中连通分量大小最大的分量大小不超过3)
可以考虑枚举图中三种连通分量的个数(设为n1,n2,n3)
设g(n1,n2,n3)为图中含有n1个大小为1的连通分量(x1),n2个……(x2),n3个……(x3)的概率。
则ans = 1-sum{ g(n1,n2,n3) | n1+n2 * 2+n3 * 3=N }
P=P/1000
有C(N,n1)种方法选出n1所在的位置,然后有C(N-n1,n2*2)种方法选出n2所在的位置,最后n3的位置就是确定的了。
所以对于确定的n1,n2,n3,一共有C(N,n1) * C(N-n1,n2*2)种选法选出三种连通分量各自所在的位置。
这些方法都是独立的,相加,但是三个分量的形成是同时发生的,所以三种分量各自在对应大小的区间形成的概率应该相乘。
关键问题:怎么计算在给定数量的位置中全都形成大小为1/2/3的连通分量的概率。
图中有n个点的时候:
某一个点自己形成一个大小为1的连通分量x1的概率P1(n)=(1-P)^(n-1)(跟这个点有关的边有n-1条,所有的都没有出现)
某两个点一起形成一个大小为2的连通分量x2的概率P2(n)=P*(1-P)^(2n-4)(跟这两个点有关的边有2N-3条,其中只有连接这两个点的出现了,其他的都没出现)
某三个点一起形成一个大小为3的连通分量x3的概率P3(n)=3 * P * P * (1-P)^(3n-8)+P * P * P * (1-P)^(3n-9)
(跟这三个点有关的边有3N-6条,可能只需要两条边三个点就连在一起了,这个时候出现2条,三种方式,有3N-8条没有出现;还有可能有三条边把这三个点连接在一起)
但是假如现在有k个点,要计算这k个点全部都是大小为1的连通分量的概率的话P1^k这个答案是不正确的,重复计算了每一条边的概率贡献。
应该递归计算。
设f1(k)表示在k个点中只存在x1的概率,f1(k)=C(k-1,0) * P1(k) * f1(k-1)
设f2(k)表示在k个点中只存在x2的概率,f2(k)=C(k-1,1) * P2(k) * f2(k-2)
设f3(k)表示在k个点中只存在x3的概率,f3(k)=C(k-1,2) * P3(k) * f3(k-3)
这样递归计算的话每条边对概率的贡献就不会重复计算了。
对于每一种n1,n2,n3,内部是独立的可以用递推来计算,但是这三个板块之间的边的概率还没有考虑到(当然全部都没有出现)。
一共有n1 * (n2 * 2+n3 * 3)+n2 * n3 * 6条跨越板块的边没有出现,这种情况的概率P4=(1-P)^(n1 * (n2 * 2+n3 * 3)+n2 * n3 * 6)
所以说对于一种n1,n2,n3的方案的概率就出来了:
g(n1,n2,n3)=C(N,n1) * C(N-n1,n2 * 2) * P4 * f1(n1) * f2(n2 * 2) * f3(n3 * 3)
然而组合数太大了,方便起见直接取了阶乘的自然对数来算,最后算答案的时候乘方算回来就可以了。
AC代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<set> #include<map> #include<queue> #include<vector> #include<cctype> using namespace std; const int maxn=105; int N; double P; long double C[maxn][maxn],ln[maxn]; long double f1[maxn],f2[maxn],f3[maxn],P1[maxn],P2[maxn],P3[maxn]; double ans; void get_C() { ln[0]=log(1); for(int i=1;i<=N;i++) ln[i]=ln[i-1]+log(i); for(int i=0;i<=N;i++) { C[i][0]=log(1); for(int j=1;j<=i;j++) C[i][j]=ln[i]-ln[i-j]-ln[j]; } } long double qkpow(long double x,int y) { return log(x)*y; } void ready() { f1[0]=f2[0]=f3[0]=log(1); for(int k=1;k<=N;k++) { P1[k]=qkpow(1-P,k-1); f1[k]=C[k-1][0]+P1[k]+f1[k-1]; } for(int k=2;k<=N;k+=2) { P2[k]=log(P)+qkpow(1-P,2*k-4); f2[k]=C[k-1][1]+P2[k]+f2[k-2]; } for(int k=3;k<=N;k+=3) { P3[k]=log(3*P*P*exp(qkpow(1-P,3*k-8))+P*P*P*exp(qkpow(1-P,3*k-9))); f3[k]=C[k-1][2]+P3[k]+f3[k-3]; } } int main() { freopen("test.in","r",stdin); freopen("test.out","w",stdout); scanf("%d%lf",&N,&P); P/=1000; get_C(); ready(); long double P4=0; for(int n1=0;n1<=N;n1++) for(int n2=0;n2*2<=N;n2++) { if(N-n1-n2*2<0 || (N-n1-n2*2)%3!=0) continue; int n3=(N-n1-n2*2)/3; P4=qkpow(1-P,n1*(n2*2+n3*3)+n2*n3*6); ans+=exp(C [n1]+C[N-n1][n2*2]+P4+f1[n1]+f2[n2*2]+f3[n3*3]); } printf("%.4lf",1-ans); return 0; }
相关文章推荐
- Codeforces 28C Bath Queue - 动态规划 - 组合数学 - 概率与期望
- best coder #35-01<组合数学 || 概率数学>
- 【loli的胡策】训练1.14(组合数学+概率期望+乱搞)
- 一些概率条件判断和组合数学题
- 面试题[数学与概率]: 从数据流中随机选一个数
- HDU 4254 A Famous Game (概率&组合数学公式)
- UVa 11021 Tribles (概率DP + 组合数学)
- 51nod 1667 概率好题 组合数学+容斥原理
- 2017.3.10组合数学学习——多重集合的排列、组合,有限概率
- 概率统计、组合数学等专项练习
- [数学] 将长为L的木棒随机折成3段,则3段构成三角形的概率
- Bin & Jing in wonderland(概率,组合数学)
- HDU5810(2016多校第七场)——Balls and Boxes(组合数学,概率)
- HDOJ 2200 Eddy's AC难题(数学组合概率题)
- HDOJ 2200 Eddy's AC难题(数学组合概率题)
- codeforces B. Dreamoon and WiFi 组合数学求概率
- 51nod 1667 概率好题 组合数学+容斥原理
- Codeforces 626D Jerry's Protest 「数学组合」「数学概率」
- hdu 4045 Machine scheduling 组合数学
- 2014ACM/ICPC亚洲区西安站 F题 color (组合数学,容斥原理)