传球(概率问题)

传球

问题描述:
N个人坐成一圈, 其中第K个人拿着一个球。 每次每个人会以一定的概率向
左边的人和右边的人传球。 当所有人都拿到过球之后, 最后一个拿到球的人即为胜者。 求第N个人获胜的概率。( 所有人按照编号逆时针坐成一圈)
输入格式:
第一行一个数T代表数据组数。
对于每组数据, 第一行两个整数N, K如题意所述。
接下来每行一个实数p代表该人将球传给右边的人的概率。
输出格式:
对于每组数据, 一行一个实数代表答案, 保留9位小数。
样例输入:
1
5 1
0.10
0.20
0.30
0.40
0.50
样例输出:
0.007692308
数据规模与约定:
对于20%的数据, N ≤ 3。
对于70%的数据, T, N ≤ 100。
对于100%的数据, T ≤ 10000,1 ≤ N ≤ 100。

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=110;
int t,n,k,pre[maxn],next[maxn];
long double l[maxn],r[maxn];
void deal(int b)
{
    int a=pre[b],c=next[b];
    long double ra=r[a]*r[b]/(1-r[a]*(1-r[b]));
    long double lc=(1-r[c])*(1-r[b])/(1-(1-r[c])*r[b]);
    r[a]=ra;l[a]=1-r[a];l[c]=lc;r[c]=1-l[c];
    next[a]=c;pre[c]=a;
}
long double work()
{
    if(n<=2) return 1;
    if(n<=3) return k==1 ? r[1]:l[2];
    for(int i=1;i<=n;i++)
    pre[i]=i-1,next[i]=i+1;
    pre[1]=n;next[n]=1;
    if(k==1)
    {
        for(int i=2;i<n-1;i++)
        deal(i);
        return r[1];
    }
    if(k==n-1)
    {
        for(int i=2;i<n-1;i++)
        deal(i);
        return l[n-1];
    }
    for(int i=2;i<k;i++)
    deal(i);
    for(int i=k+1;i<n-1;i++)
    deal(i);
    deal(k);
    return l[k]*r[1]+r[k]*l[n-1];
}
int main()
{
    freopen("it.in","r",stdin);
    freopen("it.out","w",stdout);
    cin>>t;
    while(t--)
    {
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            double x;
            scanf("%lf",&x);
            r[i]=x;
            l[i]=1-r[i];
        }
        printf("%0.9lf
",(double)work());
    }
    fclose(stdin);fclose(stdout);
    return 0;
}
原文地址:https://www.cnblogs.com/cax1165/p/6070903.html