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

状压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;
}

  

原文地址:https://www.cnblogs.com/IMGavin/p/5740656.html