• 「BZOJ 3270」博物馆「高斯消元」


    应该算高斯消元经典题了吧。

    题意:一个无向连通图,有两个人分别在(s,t),若一个人在(u),每一分钟有(p[u])的概率不动,否则随机前往一个相邻的结点,求在每个点相遇的概率

    题解

    首先求一个(mov[i]=frac{1-p[i]}{deg[i]})表示结点i每次移动到某个相邻结点的概率,(deg[i])表示结点(i)的度

    为了方便,我们把每个点向自己连条边,下面写式子好些(注意度数不能增加)

    然后考虑设计状态(f(a,b))表示第一个人在(a),第二个人在(b)的概率

    [f(a,b)=sum_{(u,a),(v,b),u ot =v}g(u,a)g(v,b) ]

    其中(g(a,b))表示(a)(b)的概率,当(a=b)时为(p[a]),否则为(mov[a])

    然后把二元组映射到大小为(n^2)的一维数组,高斯消元,注意(f(s,t)=1)

    时间复杂度:(O(n^6))

    #include <algorithm>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    using namespace std;
    
    const int N = 25;
    
    int n, m, s, t, deg[N];
    double mov[N], p[N];
    vector<int> G[N];
    
    double calc(int u, int v) {
        return u == v ? p[u] : mov[u];
    }
    
    int pos(int u, int v) {
        return (u - 1) * n + v;
    }
    
    double a[N * N][N * N];
    
    void gauss(int n) {
        for(int i = 1, j = 1; i <= n; j = ++ i) {
            for(int k = i + 1; k <= n; k ++) if(fabs(a[j][i]) < fabs(a[k][i])) j = k;
            if(i != j) for(int k = i; k <= n + 1; k ++) swap(a[j][k], a[i][k]);
            for(j = i + 1; j <= n; j ++) {
                double z = a[j][i] / a[i][i];
                for(int k = i; k <= n + 1; k ++) a[j][k] -= z * a[i][k];
            }
        }
        for(int i = n; i >= 1; i --) {
            for(int j = i + 1; j <= n; j ++) a[i][n + 1] -= a[j][n + 1] * a[i][j];
            a[i][n + 1] /= a[i][i];
        }
    }
    
    int main() {
        scanf("%d%d%d%d", &n, &m, &s, &t);
        for(int u, v, i = 1; i <= m; i ++) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
            deg[u] ++; deg[v] ++;
        }
        for(int i = 1; i <= n; i ++) {
            scanf("%lf", p + i);
            G[i].push_back(i);
            mov[i] = (1 - p[i]) / deg[i];
        }
        int k = n * n;
        for(int i = 1; i <= n; i ++) {
            for(int j = 1; j <= n; j ++) {
                int p = pos(i, j); a[p][p] = -1;
                if(i == s && j == t) a[p][k + 1] = -1;
                for(int x = 0; x < G[i].size(); x ++) {
                    int u = G[i][x];
                    for(int y = 0; y < G[j].size(); y ++) {
                        int v = G[j][y];
                        if(u == v) continue ;
                        a[p][pos(u, v)] += calc(u, i) * calc(v, j);
                    }
                }
            }
        }
        gauss(k);
        for(int i = 1; i <= n; i ++)
            printf("%.6f ", a[pos(i, i)][k + 1]);
        return 0;
    }
    
    
  • 相关阅读:
    java.lang.ArrayIndexOutOfBoundsException异常分析及解决
    Android_开发片段(Part 2)
    保存错误日志回传服务器之回传错误“信息文件”
    node.js
    拼接json
    CommonJS / Node.js/ Vue学习资料
    合并PDF
    java 多线程
    linux 运行jar包
    mvn 命令
  • 原文地址:https://www.cnblogs.com/hongzy/p/10356410.html
Copyright © 2020-2023  润新知