Codeforces Round #363 LRU(概率 状压DP)

时间:2021-07-04 00:32:45

状压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("\n");
}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<<"#\n";
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("\n"); } return 0;
}