Lucky Coins HDU - 5985
Bob has collected a lot of coins in different kinds. He wants to know which kind of coins is lucky. He finds out a lucky kind of coins by the following way. He tosses all the coins simultaneously, and then removes the coins that come up tails. He then tosses all the remaining coins and removes the coins that come up tails. He repeats the previous step until there is one kind of coins remaining or there are no coins remaining. If there is one kind of coins remaining, then this kind of coins is lucky. Given the number of coins and the probability that the coins come up heads after tossing for each kind, your task is to calculate the probability for each kind of coins that will be lucky.
Input
The first line is the number of test cases. For each test case, the first line contains an integer k representing the number of kinds. Each of the following k lines describes a kind of coins, which contains an integer and a real number representing the number of coins and the probability that the coins come up heads after tossing. It is guaranteed that the number of kinds is no more than 10, the total number of coins is no more than 1000000, and the probabilities that the coins come up heads after tossing are between 0.4 and 0.6.
Output
For each test case, output a line containing k real numbers with the precision of 6 digits, which are the probabilities of each kind of coins that will be lucky.
Sample Input
3
1
1000000 0.5
2
1 0.4
1 0.6
3
2 0.4
2 0.5
2 0.6
Sample Output
1.000000
0.210526 0.473684
0.124867 0.234823 0.420066
题意:
给你n种硬币,并给你每种硬币的个数和正面朝上的概率。每次将所有的硬币投掷一下。背面朝上的抛弃。直到只剩下一种硬币或者没有硬币。最后剩下的那种硬币叫幸运硬币,问每种硬币成为幸运硬币的概率。
分析:
设两个函数
killed[i][j]=(1−pki)nikilled[i][j]=(1−pik)ni
表示第i种硬币到第k步时全部死光
也就是对于一枚i硬币来说正面朝上的概率为pipi,那么k次实验,仍然不死说明k次全部正面朝上,所以是pkipik,然后用1减去就是k步全部死光的概率,共有nini枚硬币,所以根据乘法原理,需要全部乘起来,就得到了上面的公式
设
recv[i][j]=1−killed[i][j]recv[i][j]=1−killed[i][j]
表示第i种硬币到第k步时至少有一个活着,因为我们上面知道了i种硬币到达第k步全部死光的概率,因此用1一减就得到至少一个活着的概率
因此每种硬币i成为幸运硬币的概率,就是对于每一步而言,其他硬币全死光,只剩下i中至少一个存活
ans[i]=∑maxj=1(recv[i][j]−recv[i][j+1])×∏nk=0,k!=ikilled[k][j]ans[i]=∑j=1max(recv[i][j]−recv[i][j+1])×∏k=0,k!=inkilled[k][j]
上式中的recv[i][j]−recv[i][j+1]recv[i][j]−recv[i][j+1]为了确切知道第j步时i硬币存活的概率而避免重复
code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 75;
const int maxm = 15;
int t,n;
int num[maxm];
double p[maxm];
double killed[maxm][maxn+5];
double recv[maxm][maxn+5];
double ans[maxm];
void solve(){
int i,j,k;
for(i = 0; i < maxm; i++){
ans[i] = 0.0;
}
if(n == 1){
printf("%.6f\n",1.0);
return;
}
for(i = 0; i < n; i++){
double tmp = p[i];
for(j = 1; j <= maxn; j++){
killed[i][j] = pow(1-tmp,num[i]);
recv[i][j] = 1 - killed[i][j];
tmp *= p[i];
}
}
for(i = 0; i < n; i++){
for(j = 1; j < maxn; j++){
double tmp = 1.0;
for(k = 0; k < n; k++){
if(k != i) tmp *= killed[k][j];
}
ans[i] += (recv[i][j] - recv[i][j+1]) * tmp;
}
}
for(i = 0; i < n; i++){
printf("%.6f%c",ans[i],i == n-1 ? '\n' : ' ');
}
return;
}
int main(){
int i;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i = 0; i < n; i++){
scanf("%d%lf",&num[i],&p[i]);
}
solve();
}
return 0;
}