Solution -「CF113D」Museum

Upd 2021.10.21 更改了状态定义。

(S(u)) 表示 (u) 结点的相邻结点的集合。

又记 (p(u)) 表示走到了 (u) 且下一步继续留在 (u) 结点的概率,那么下一步离开 (u) 结点的概率即为 (1 - p(u))

(f(i, j)) 表示 Petya 在 (i) 且 Vasya 在 (j) 这种状态的期望出现次数。

可知所有的形如 (f(i, i)) 的状态都是不能用于转移的,因为它们已经是末状态了。

因为钦定了末状态只出现一次,故可知末状态的期望出现次数即该状态的概率。

故有

[f(i, j) = sum_{k in S(i), k eq j} f(k, j) imes frac{1 - p(k)} {|S(k)|} imes p(j) + sum_{k in S(j), k eq i} f(i, k) imes frac{1 - p(k)} {|S(k)|} imes p(i) + sum_{u in S(i), v in S(j), u eq v} f(u, v) imes frac{1 - p(u)} {|S(u)|} imes frac{1 - p(v)} {|S(v)|} ]

显然这个转移是有后效性的,无法用简单的递推做。故考虑高斯消元,将该式转换为我们熟悉的方程形式进行求解即可。

共有 (n ^ 2) 只方程,时间复杂度 (O(n ^ 6))

因为一开始处于初始状态,故初始状态期望出现次数自带 (1)

#include <cstdio>
#include <vector>
using namespace std;

int Abs(int x) { return x < 0 ? -x : x; }
int Max(int x, int y) { return x > y ? x : y; }
int Min(int x, int y) { return x < y ? x : y; }

int read() {
    int x = 0, k = 1;
    char s = getchar();
    while (s < '0' || s > '9') {
        if (s == '-')
            k = -1;
        s = getchar();
    }
    while ('0' <= s && s <= '9') {
        x = (x << 3) + (x << 1) + (s ^ 48);
        s = getchar();
    }
    return x * k;
}

void write(int x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

void print(int x, char c) {
    write(x);
    putchar(c);
}

const int MAXN = 23 * 23 + 5;

struct Elimination {
    bool free[MAXN];
    int n, m, rk, opt;
    double a[MAXN][MAXN], eps;
    Elimination() { eps = 1e-15; }
    Elimination(int N, int M) {
        n = N;
        m = M;
    }
    double Abs(double x) { return x < eps ? -x : x; }
    void Swap(double &x, double &y) {
        double t = x;
        x = y;
        y = t;
    }

    void clear() {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++) a[i][j] = 0;
    }

    void calc() {
        int r = 1, c = 1;
        for (; r <= n && c <= m; r++, c++) {
            int pos = r;
            for (int i = r + 1; i <= n; i++)
                if (Abs(a[i][c]) > Abs(a[pos][c]))
                    pos = i;
            if (Abs(a[pos][c]) < eps) {
                r--;
                continue;
            }
            if (pos != r)
                for (int i = c; i <= m; i++) Swap(a[r][i], a[pos][i]);
            double t;
            for (int i = 1; i <= n; i++)
                if (i != r && Abs(a[i][c]) > eps) {
                    t = a[i][c] / a[r][c];
                    for (int j = m; j >= c; j--) a[i][j] -= t * a[r][j];
                }
        }
        rk = r;
    }
};

int deg[MAXN];
double p[MAXN];
vector<int> mp[MAXN];

void Add_Edge(int u, int v) {
    mp[u].push_back(v);
    mp[v].push_back(u);
}

struct node {
    int x, y;
    node() {}
    node(int X, int Y) {
        x = X;
        y = Y;
    }
    int Get(int n) { return (x - 1) * n + y; }
};

int main() {
    int n = read(), m = read(), x = read(), y = read();
    for (int i = 1, u, v; i <= m; i++) {
        u = read(), v = read();
        Add_Edge(u, v);
        deg[u]++, deg[v]++;
    }
    for (int i = 1; i <= n; i++) scanf("%lf", &p[i]);
    Elimination q;
    q.n = n * n;
    q.m = q.n + 1;
    q.clear();
    q.a[node(x, y).Get(n)][q.m] = -1;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            int pos = node(i, j).Get(n);
            q.a[pos][pos]--;
            if (i != j)
                q.a[pos][pos] += p[i] * p[j];
            for (size_t k1 = 0; k1 < mp[i].size(); k1++)
                for (size_t k2 = 0; k2 < mp[j].size(); k2++) {
                    int u = mp[i][k1], v = mp[j][k2];
                    if (u == v)
                        continue;
                    q.a[pos][node(u, v).Get(n)] += (1 - p[u]) * (1 - p[v]) / deg[u] / deg[v];
                }
            for (size_t k = 0; k < mp[i].size(); k++)
                if (mp[i][k] != j)
                    q.a[pos][node(mp[i][k], j).Get(n)] += (1 - p[mp[i][k]]) / deg[mp[i][k]] * p[j];
            for (size_t k = 0; k < mp[j].size(); k++)
                if (mp[j][k] != i)
                    q.a[pos][node(i, mp[j][k]).Get(n)] += (1 - p[mp[j][k]]) / deg[mp[j][k]] * p[i];
        }
    q.calc();
    for (int i = 1; i <= n; i++)
        printf("%.9f
", q.a[node(i, i).Get(n)][q.m] / q.a[node(i, i).Get(n)][node(i, i).Get(n)]);
    return 0;
}
原文地址:https://www.cnblogs.com/Chain-Forward-Star/p/15413618.html