题目大意
有n个小朋友,编号1到n。每个小朋友有Bi个朋友(1<=i<=n)。现要选出的3个小朋友都互为朋友,或都不是朋友。求任意选出3人满足条件的概率。
题解
简单分析一下可以发现,题目没有告诉具体的关系。那要求概率只能用组合数学。该题有两种思考方向,一种直接求满足条件的方案数,一种是反着求不满足条件的方案数。
1. 正向求解
易知,任意选出3个人他们之间的关系有且只有以下4种情况:1)三人互为朋友;2)三人都不是朋友;3)三个人中只有两个人是朋友;4)三个人中只有两个人不是朋友;
我们设总方案数为, 情况1)的方案数为:A,情况2)为B,情况3)为C,情况4)为D,则z = A+B+C+D。
如果我们从每个人的朋友中选两人 ,那么加上这个人,这三人的关系就可能为情况1)或情况4);
对每一个人都做如上操作,并求和得到方案数,且X=3*A+D。3*A是因为情况1)再计算时被充分计算了3次。
同理,如果我们从每个的非朋友中选两人,并对每一个人做同样的操作,最后在求和。便可得到,且Y=3*B+C。
之后,有z = A+B+C+D,X=3*A+D和Y=3*B+C便可解出,那么概率
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int arr[1002];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
for(int i = 0; i<n; i++){
scanf("%d", arr+i);
}
int z = n*(n-1)*(n-2)/6;
int x = 0, y = 0;
for(int i = 0; i<n; i++){
y += arr[i]*(arr[i]-1)/2;
x += (n-arr[i]-1)*(n-arr[i]-2)/2;
}
printf("%.3f\n", 1.0*(x+y-z)/2/z);
}
}
2. 反向求解
对于每一个人,我们都从他的朋友中取一人,再从他非朋友中取一人。通过这种方式选出的三人的关系为情况3)或情况4),且都重复计算了2次。则对每一个人做同样的操作,并求和得到方案数: = 2*(C+D)。
所以概率
代码如下:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int arr[1002];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
for(int i = 0; i<n; i++){
scanf("%d", arr+i);
}
int tol = n*(n-1)*(n-2)/6;
int fail = 0;
for(int i = 0; i<n; i++){
fail+=(arr[i]*(n-arr[i]-1));
}
printf("%.3f\n", 1.0*(tol-1.0*fail/2)/tol);
}
}