AOJ 2345 : Network Reliability
問題文 : Network Reliability | Aizu Online Judge
概要
無向グラフと整数 が与えられる.の各枝が独立にパーセントの確率で消失するとき,グラフが連結である確率を求めよ.
制約
コメント
制約からbitDPを思い浮かべるところまではすぐなんだけど,部分問題に落とすところで非常に苦戦してしまったのでメモ.
解法
部分グラフ が連結である確率とおく.求めたいのはである.
しかしこのままではあまりいい性質がないので,と一致する別の量を考えてみる.
グラフが連結であるとは,ある頂点を固定したときに,からの任意の頂点に到達可能,すなわちの属する連結成分の頂点集合がに一致することである.
すなわち,
とおくと,となる.
この言い換えを行うことで,
と変形できる.ここでは頂点集合と頂点集合の間の枝の総数である.
よって,各状態について部分集合全体の和をとればよい.ビットの2進数で,ビットが1,ビットが0であるものは通りあり,そのビットを集合と見たときに部分集合は通りあるので,状態遷移の回数は
となる.よって時間でこの問題が解けた.
コード
#include <bits/stdc++.h> using namespace std; int n, m; int cnt[14][14]; int cntS[1 << 14]; double memo[1 << 14], p; // P(V : univ and equiv_class(0) == V) = 1 - P(V : univ and equiv_class(0) != V) // = 1 - Σ_{V' : proper subset of V} P(V : univ and equiv_class(0) == V') // = 1 - Σ_{V' : proper subset of V} P(V \ V' and V' is disconnected and V' : univ and equiv_class(0) == V') double calc(int bit) { if (bit == 1) return 1; if (memo[bit] >= 0) return memo[bit]; double ret = 1; for (int i = bit; i; i = (bit & (i - 1))) { if (i == bit || i % 2 == 0) continue; ret -= pow(p, cntS[bit] - cntS[i] - cntS[bit & ~i]) * calc(i); } return memo[bit] = ret; } int main() { scanf("%d %d %lf", &n, &m, &p); p /= 100; for (int i = 0; i < m; i++) { int a, b; scanf("%d %d", &a, &b); cnt[a - 1][b - 1]++; cnt[b - 1][a - 1]++; } for (int i = 0; i < (1 << n); i++) memo[i] = -1; for (int i = 0; i < (1 << n); i++) { for (int j = 0; j < n; j++) { for (int k = j; k < n; k++) { if (((i >> j) & 1) && ((i >> k) & 1)) cntS[i] += cnt[j][k]; } } } printf("%.10f\n", calc((1 << n) - 1)); return 0; }