#题意简述
一个无向图,节点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,因为初始还有一次。有了这些方程后高斯消元即可。
#参考代码
 | 
 | 
 | 
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); | 
     | 
        freopen("testdata.in", "r", stdin); | 
     | 
    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; | 
} |