题意:要收集n张卡片,得到每张卡片的概率为pi,所有的pi之和不一定为1
思路:这题的N只有20,所以可以用状态压缩,由于数学知识不给力,思路是队友给的,设所有卡片的集合为U,已经拥有的卡片集合为S,初始态S = { },最终的状态为S = U, 状态转移为dp[i] = 1 + p1*dp[j1] + p2*dp[j2]............其中dp[i] 表示状态为i的期望,状态j是从状态U- i 中选取一张卡片得到的状态,注意这里pi和不为1,此外,题目说误差小于10e-4,那么至少保留5位小数
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define N 20
#define inf 0x7ffffff
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
double p[N];
double sump;
double dp[1<<N];
int n;
double dfs(int k)
{
if(dp[k] != -1) return dp[k];
dp[k] = 1.0;
int i;
sump = 1.0;
for(i = 0; i < n; i++)
if(( k&(1<<i) ) == 0){
dp[k] += p[i]*dfs(k|(1<<i));
sump -= p[i];
}
dp[k] =dp[k] / ((1.0-sump));
return dp[k];
}
int main()
{
// ios::sync_with_stdio(false);
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
while(scanf("%d",&n) != EOF)
{
int i;
for(i = 0; i < n; i++)
scanf("%lf",&p[i]);
for(i = 0; i < (1<<n); i++)
dp[i] = -1;
dp[(1<<n)-1] = 0;
dfs(0);
printf("%lf\n",dp[0]);
}
return 0;
}