题目描述
小时候,谷学长买了很多干脆面,因为一旦集齐所有类型的卡片就有大奖可拿。
谷学长很聪明的意识到要想集齐全套卡片就得买相当多的干脆面,为了尽可能的省钱,他想计算出每种类型卡片均获得一张应买干脆面的期望数目。
输入描述
每个测试用例的第一行包含一个N(1 <= N <= 20), 表示干脆面里可能放置N种类型的卡片,第二行有N个数p1, p2, ..., pN, (p1 + p2 + ... + pN <= 1), 表示中到对应类型卡片的概率。
注意每袋干脆面最多只有一张卡片。
输出描述
对于每组测试用例,输出集齐N张不同类型的卡片所买干脆面的期望数目。结果保留三位有效数字。
样例输入
1 0.1 2 0.1 0.4
样例输出
10.000 10
规律:使用容斥原理+位元素枚举
假设有3个元素,abc
那么他们的全部就是
a+b+c-ab-ac-bc+abc
再往下推会发现
偶数个元素如ab是被减的
奇数个元素如abc是被加的
使用(i&(1<<j))!=0以按位与进行二进制判断组合中元素的个数,当所有组合子集循环完毕,最后结果便得出。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
double answer=0;
int n = sc.nextInt();
double a[] = new double[n];
for(int i=0;i<n;i++){
a[i] = sc.nextDouble();//将读取的数据存储到数组中
}
for(int i=0;i<(1<<n);i++){ //对每组排列组合子集进行判断
double sum = 0;
int counter=0;
for(int j=0;j<=n;j++){
if((i&(1<<j))!=0){ //判断子集包含元素
sum+=a[j];
counter++;
}
}
if(counter%2==0&&sum!=0){ //元素为偶数相减
answer-=1/sum;
}else if(counter%2!=0&&sum!=0){ //元素为奇数相加
answer+=1/sum;
}
}
System.out.printf("%.3f\n",answer);
}
}
}