状压DP:
先不考虑数量k, dp[i]表示状态为i的概率,状态转移方程为dp[i | (1 << j)] += dp[i],最后考虑k, 状态表示中1的数量为k的表示可行解。
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<vector> #include<cmath> #include<utility> using namespace std; typedef long long LL; const int N = 1008, INF = 0x3F3F3F3F; #define MS(a, num) memset(a, num, sizeof(a)) #define PB(A) push_back(A) #define FOR(i, n) for(int i = 0; i < n; i++) double dp[1 << 21]; double ans[30]; double p[30]; int main(){ int n, k; cin>>n>>k; int cnt = 0; for(int i= 0; i < n; i++){ scanf("%lf", &p[i]); if(p[i] < 1e-6){ cnt++; } } k = min(k, n - cnt); if(n <= k){ printf("1.0"); for(int i = 1; i < n; i++){ printf(" 1.0"); } printf(" "); }else{ dp[0] = 1; for(int i = 0; i < (1 << n); i++){ double sum = 0; for(int j = 0; j < n; j++){ if((i & (1 << j) ) == 0){ sum += p[j]; } } //cout<<sum<<"# "; for(int j = 0 ; j < n; j++){ if( (i & (1 << j) ) == 0){ dp[i | (1 << j)] += dp[i] * p[j] / sum; } } } for(int i = 0; i < (1 << n); i++){ int cnt = 0; int tp = i; while(tp){ cnt++; tp = tp & (tp - 1); } if(cnt == k){ for(int j = 0; j < n; j++){ if(i & (1 << j)){ ans[j] += dp[i]; } } } } printf("%.8f", ans[0]); for(int i = 1; i < n; i++){ printf(" %.8f", ans[i]); } printf(" "); } return 0; }