FZU 2103 排列组合

本文介绍了一个有趣的概率问题:在一个充满礼物的仙境中,主人公Bin通过喊出特定口号获得礼物,并从中挑选最好的几件送给Jing。文章详细阐述了如何计算在已知最终挑选的礼物列表情况下,这些礼物被选中的概率。

Problem Description
Bin has a dream that he and Jing are both in a wonderland full of beautiful gifts. Bin wants to choose some gifts for Jing to get in her good graces.


There are N different gifts in the wonderland, with ID from 1 to N, and all kinds of these gifts have infinite duplicates. Each time, Bin shouts loudly, “I love Jing”, and then the wonderland random drop a gift in front of Bin. The dropping probability for gift i (1≤i≤N) is P(i). Of cause, P(1)+P(2)+…+P(N)=1. Bin finds that the gifts with the higher ID are better. Bin shouts k times and selects r best gifts finally.


That is, firstly Bin gets k gifts, then sorts all these gifts according to their ID, and picks up the largest r gifts at last. Now, if given the final list of the r largest gifts, can you help Bin find out the probability of the list?

 Input
The first line of the input contains an integer T (T≤2,000), indicating number of test cases.


For each test cast, the first line contains 3 integers N, k and r (1≤N≤20, 1≤k≤52, 1≤r≤min(k,25)) as the description above. In the second line, there are N positive float numbers indicates the probability of each gift. There are at most 3 digits after the decimal point. The third line has r integers ranging from 1 to N indicates the finally list of the r best gifts’ ID.

 Output
For each case, output a float number with 6 digits after the decimal points, which indicates the probability of the final list.
 Sample Input
4
2 3 3
0.3 0.7
1 1 1
2 3 3
0.3 0.7
1 1 2
2 3 3
0.3 0.7
1 2 2
2 3 3
0.3 0.7
2 2 2
 Sample Output
0.027000
0.189000
0.441000
0.343000


思路:
k>r时,多余的k不能掉落比最小值编号小的礼物,所以记录最小值以及小于最小值的记录。然后按每个编号的数量排列组合。

代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
int N,K,R;
int num[100];
double p[100];

double C(int n,int m)
{
    double sum=1.0;
    int i,j;
    for(i=m; i>=m-n+1; i--)
    {
        sum*=1.0*i;
    }
    for(j=1; j<=n; j++)
    {
        sum/=(1.0*j);
    }
    return sum;
}


int min(int a,int b)
{
 if(a>b)
 return b;
 else
 return a;
}

int main()
{
    int t,Minid;
    int i,j,rem,k;
 double pp,p1,pro,ans;
    scanf("%d",&t);
    while(t--)
    {
        Minid=6666666;
        scanf("%d %d %d",&N,&K,&R);
        memset(num,0,sizeof(num));
        for(i=1; i<=N; i++)
        {
            scanf("%lf",&p[i]);
        }
        for(i=1; i<=R; i++)
        {
            int temp;
            scanf("%d",&temp);
            num[temp]++;
            Minid=min(Minid,temp);
        }
        k=K;
        pro=0;
        for(i=1; i<Minid; i++)
        {
            pro+=p[i];
        }
        ans=0;
        
        for(j=0; j<=K-R; j++)
        {
            p1=1.0;
            num[Minid]+=j;
            k=K;
            for(i=1; i<=N; i++)
            {
                if(num[i])
                {
                    p1=p1*C(num[i],k)*pow(p[i],num[i]);
                    k-=num[i];
                }
            }
            pp=p1;
            rem=K-R-j;
		//剩下的次数只能掉落小于等于最小值的,仍要计算概率
            while(rem>0)
            {
                pp*=pro;
                rem--;
            }
            ans+=pp;
            num[Minid]-=j;
        }
        printf("%.6f\n",ans);
    }
    return 0;
}


 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值