CF446D DZY Loves Games

https://www.luogu.com.cn/problem/CF446D

首先肯定是转换为求出 g [ i ] [ j ] g[i][j] g[i][j]表示从第 i i i个陷阱到第 j j j个陷阱,不经过其他陷阱(相当于是走一步)的概率;
1单独处理一下
然后把这个矩阵 k − 2 k-2 k2次方即可(走k-1步)

然后现在来考虑怎么求出 g g g

把所有关键点的出边全部删掉
f [ i ] [ j ] f[i][j] f[i][j]表示原图的第 i i i个点(不是关键点),到第 j j j个关键点的概率
这个跑 n n n次高斯消元(对于每个结束点跑一次)就可以得出来以每个关键点结束的概率

然后 g [ i ] [ j ] g[i][j] g[i][j]就枚举 i i i的出边 v v v然后通过f来求出

这样是 O ( n 4 ) O(n^4) O(n4),不太行

容易发现,对于每个结束点的矩阵(方程组),只有最后一列(常数)是不同的
所以可以吧常数项全部丢到后面,一次消元,一次性全部求出来

具体实现看代码吧
code:

#include<bits/stdc++.h>
#define N 605
using namespace std;
int tot;
struct MT {
    double a[105][105];
    void clear() {
        for(int i = 0; i <= tot; i ++)
            for(int j = 0; j <= tot; j ++) a[i][j] = 0;
    }
    void I() {
        for(int i = 1; i <= tot; i ++) a[i][i] = 1;
    }
} ans, b;
MT mul(MT a, MT b) {
    MT c; c.clear();
    for(int k = 1; k <= tot; k ++)
        for(int i = 1; i <= tot; i ++)
            for(int j = 1; j <= tot; j ++)
                c.a[i][j] += a.a[i][k] * b.a[k][j];
    return c;
}
MT qpow(MT x, int y) {
    MT ret; ret.clear(); ret.I();
    for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ret = mul(ret, x);
    return ret;
}
double a[N][N];
int o[N], p[N], d[N], gs[N][N], n, m, k;
void Guass(int n) {
    for(int i = 1; i <= n; i ++) {
        int j = i;
        for(int k = i + 1; k <= n; k ++) if(abs(a[j][i]) < abs(a[k][i])) j = k;
        if(j != i) swap(a[j], a[i]);
        double d = a[i][i];
        for(int j = i; j <= n + tot; j ++) a[i][j] /= d;
        for(int j = 1; j <= n; j ++) {
            if(j == i) continue;
            double t = a[j][i] / a[i][i];
            for(int k = i; k <= n + tot; k ++)
                a[j][k] -= t * a[i][k];
        }
    }
}
int main() {
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= n; i ++) {
        scanf("%d", &o[i]);
        if(o[i]) p[++ tot] = i;
    }
    for(int i = 1; i <= m; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        d[u] ++, d[v] ++; gs[u][v] ++, gs[v][u] ++;
    }
    for(int i = 1; i <= n; i ++) {
        if(!o[i]) {
            a[i][i] = -1;
            for(int j = 1; j <= n; j ++) a[i][j] += 1.0 * gs[i][j] / d[i];
        } else {
            a[i][i] = 1;
            int pos = 0;
            for(int j = 1; j <= tot; j ++) if(p[j] == i) pos = j;
            a[i][n + pos] = 1;
        }
    }
//    for(int i = 1; i <= n; i ++) {
//        for(int j = 1; j <= n + tot; j ++) printf("%.2lf ", a[i][j]); printf("\n");
//    }
    Guass(n);
    for(int i = 1; i <= tot; i ++) ans.a[1][i] = a[1][n + i];
    for(int i = 1; i <= tot; i ++)
        for(int j = 1; j <= tot; j ++) {
            for(int k = 1; k <= n; k ++) b.a[i][j] += gs[p[i]][k] * a[k][j + n];
            b.a[i][j] /= d[p[i]];
        }
    ans = mul(ans, qpow(b, k - 2));
    printf("%.9lf", ans.a[1][tot]);
    return 0;
}
posted @ 2021-09-25 21:36  lahlah  阅读(131)  评论(0编辑  收藏  举报