[BZOJ 3270]博物館

題意

有兩個人在無向圖中走,初始時在(A,B)p[i] 的概率留在原地,(1p[i]) 的概率等可能的往出邊走,詢問兩個人在1~n每個房間相遇的概率
n20

分析

考慮兩個人會構成n2 種狀態(a,b)
則可以列出方程,設P(a,b) 爲經過(a,b) 這個狀態的概率
p[i] 代表留在當前點的概率,Out[i] 代表走出當前點的概率
Out[i]=(1p[i])/degree[i]
P(a,b)=p[a]p[b]P(a,b)+Out[u]p[b]P(u,b)+p[a]Out[v]P(a,v)+Out[u]Out[v]P(u,v)
- 注意到如果兩人在同一個房間的話就不可以再走了,所以當u==v的時候係數爲0
然後在狀態(A,B) 起始點的時候方程爲
P(a,b)=p[a]p[b]P(a,b)+Out[u]p[b]P(u,b)+p[a]Out[v]P(a,v)+Out[u]Out[v]P(u,v)+1
高斯消元即可

#include <bits/stdc++.h>
#define maxn 10010
#define st(i, j) (i-1)*n+j
using namespace std;

int n, m;

int deg[maxn];

struct Edge{int to, next;}edge[maxn];
int h[maxn], cnt, s, t;
void add(int u, int v){
    cnt ++;
    edge[cnt].to = v;
    edge[cnt].next = h[u];
    h[u] = cnt;
    deg[u] ++;
}

double p[maxn], Out[maxn];

double a[510][510];

void Debug(int n){
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= n + 1; j ++){
            printf("%.2lf ", a[i][j]);
        }printf("\n");
    }puts("");
}


void build(int x, int y){
    int now = st(x, y);
    a[now][now] -= 1;

    for(int i = h[x]; i; i = edge[i].next){
        for(int j = h[y]; j; j = edge[j].next){
            int u = edge[i].to, v = edge[j].to, to = st(u, v);
            if(u != v){
                if(u == x && v == y)a[now][to] += p[u] * p[v];
                else if(u == x)a[now][to] += p[u] * Out[v];
                else if(v == y)a[now][to] += Out[u] * p[v];
                else a[now][to] += Out[u] * Out[v];
            }
        }
    }
}

void Gauss(int n){
    for(int i = 1; i <= n; i ++){
        for(int j = i; j <= n; j ++)if(a[j][i]){
            for(int k = 1; k <= n + 1; k ++)
                swap(a[i][k], a[j][k]);
            for(int k = 1; k <= n + 1; k ++)
                if(k != i)a[i][k] /= a[i][i];
            a[i][i] = 1;
            break;
        }
        if(!a[i][i])continue;
        for(int j = 1; j <= n; j ++){
            if(j == i)continue;
            double t = a[j][i];
            for(int k = 1; k <= n + 1; k ++)
                a[j][k] -= t * a[i][k];
        }
    }
}

int main(){
    scanf("%d%d%d%d", &n, &m, &s, &t);
    int u, v;
    for(int i = 1; i <= m; i ++){
        scanf("%d%d", &u, &v);
        add(u, v), add(v, u);
    }

    for(int i = 1; i <= n; i ++)
        scanf("%lf", &p[i]);
    for(int i = 1; i <= n; i ++)
        Out[i] = (1 - p[i]) / deg[i];
    for(int i = 1; i <= n; i ++) add(i, i);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= n; j ++)
            build(i, j);

    a[st(s, t)][n * n + 1] = -1;

    Gauss(n * n);

    for(int i = 1; i <= n; i ++){
        int now = st(i, i);
        printf("%.6lf ", a[now][n * n + 1]);
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章