Yukicoder No.298 話の伝達

,

https://yukicoder.me/problems/no/298

想定誤解法を書いてサンプルで落ちた。

solution

標本空間から$2^N$個を全列挙して生起確率を計算し、制約を満たすものの総和を取る。$O(N 2^N)$。

$O(N + M)$のDPは想定誤解法。合流が存在するので親たちの真偽が独立でないため。

標本空間からの全列挙であれば、条件付き確率ではないので独立性うんぬんとは無縁。 確率は真となる確率$p$と偽となる確率$1-p$をいい感じに使い分けて計算すればよい。

implementation

#include <cstdio>
#include <vector>
#include <tuple>
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
using namespace std;
int main() {
    int n, m; scanf("%d%d", &n, &m);
    vector<vector<pair<int,double> > > g(n);
    repeat (i,m) {
        int a, b, c; scanf("%d%d%d", &a, &b, &c);
        g[b].emplace_back(a, c/100.0);
    }
    double ans = 0;
    repeat (s,1<<n) if ((s&(1<<0)) and (s&(1<<(n-1)))) {
        double p = 1;
        repeat (i,n) if (i != 0) {
            double cq = 1;
            for (auto it : g[i]) {
                int j; double r; tie(j, r) = it;
                if (s&(1<<j)) {
                    cq *= 1 - r;
                }
            }
            if (s&(1<<i)) {
                p *= 1 - cq;
            } else {
                p *= cq;
            }
        }
        ans += p;
    }
    printf("%.10lf\n", ans);
    return 0;
}