0%

[USACO10HOL]Driving Out the Piggies

#题意简述

一个无向图,节点1有一个炸弹,在每个单位时间内,有p/q的概率在这个节点炸掉,有1-p/q的概率随机选择一条出去的路到其他的节点上。问最终炸弹在每个节点上爆炸的概率。

#简要做法

求期望,即求每个节点炸弹经过次数的期望。设f[i]为经过i节点的次数,则有$f[u] = \sum_{(u,v)\in E}\frac{1}{deg_v}(1-\frac{p}{q})f[v]$,(意思是一个节点不爆炸就有等概率传给临边)其中f[1]还要再加1,因为初始还有一次。有了这些方程后高斯消元即可。

#参考代码

#pragma GCC optimize (3, "Ofast", "inline")
#include <bits/stdc++.h>
#define eps 1e-15
using namespace std;
const int maxn = 305;
int n, m, p, q;
vector<int> G[maxn];
double a[maxn][maxn];
void Gauss() {
    for(int i = 1; i <= n; ++i) {
        int mx = i;
        for(int j = i + 1; j <= n; ++j)
            if(fabs(a[j][i]) > fabs(a[mx][i])) mx = j;
        for(int j = i; j <= n + 1; ++j) swap(a[i][j], a[mx][j]);
        for(int j = 1; j <= n; ++j) {
            if(i == j) continue;
            double tmp = a[j][i] / a[i][i];
            for(int k = i; k <= n + 1; ++k) a[j][k] -= a[i][k] * tmp;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    #ifndef ONLINE_JUDGE
        freopen("testdata.in", "r", stdin);
    #endif
    cin >> n >> m >> p >> q;
    int u, v;
    for(int i = 1; i <= m; ++i) {
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    double P = (double)p / q;
    for(int i = 1; i <= n; ++i) {
        a[i][i] = 1;
        for(int j = 0; j < G[i].size(); ++j) {
            int to = G[i][j];
            a[i][to] -= (1 - P) / G[to].size();
        }
    }
    a[1][n + 1] = 1;
    Gauss();
    for(int i = 1; i <= n; ++i)
        cout << setprecision(9) << fixed << P * a[i][n + 1] / a[i][i] << endl;
    return 0;
}