1. 程式人生 > >[hdu5985]概率題的推導

[hdu5985]概率題的推導

題目描述

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.

演算法思路

  1. 這一題在比賽的時候我想的太多了,切分的子問題太多反而導致求解變得十分困難,最後導致我們沒有A下這一題,可以說責任在我。
  2. 思路的話十分簡單,首先,我們先計算出到達第k步的時候硬幣i死亡的概率
    kill[i][j]=(1p[i]j)num[i]
    我們就可以計算出到達第i步之後i存活的概率
    recv[i][j]=1kill[i][j]
    那麼,我們就可以得到某一個硬幣i成為lucky coins的概率
    ans[i]=j=1max(recv[i][j]recv[i][j+1)k=0,kinkill[k][j]
    這個max是如何確定呢,我們知道所有的概率都在0.4-0.6之間,而總的硬幣的個數在100000之內,我們就可以計算收斂的速度了。

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;

#define MAXN 75
#define 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() { freopen("input","r",stdin); 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; }