CF113D Museum

题意:

一张联通图,每个结点 $i$ 有一个概率 $p[i]$,当一个人在上面的时候,有 $p[i]$ 概率停留,初始时有两人分别在 $a$,$b$,问他们在每个点相遇的概率是多少。

Solution:

定义状态 $f(i,j)$ 代表一人在 $i$,一人在 $j$ 的概率,然后得到转移方程 

$f(i,j)=p_{i} \times p_{j} \times f(i,j) + \sum_{u\in son(i),u!=j}^{} \frac{(1-p(u))\times p(j) \times f(u,j)}{\left | son(u) \right | } +\sum_{u\in son(j),u!=i}^{}\frac{(1-p(u)) \times p(i) \times f(i,u)}{\left | son(u) \right |} + \sum_{u\in son(i),v\in son(j),u!=v}^{} \frac {(1-p(u))\times(1-p(v))\times f(u,v)}{\left | son(u) \right | \left | son(v) \right |} $

然后你发现,起点的 $f(a,b)$ 等于上面那个式子加一,因为一开始的缘故。

然后你又发现,这些状态相互影响,但可以解方程!所以高斯消元,给每个点对一个下标作为一个元素,然后大力消元解方程,最后答案就是每个对角线上点对对应的答案。

code :

 

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(int i=(a);i<(b);++i)
#define rrep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=0;
    while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    if(f)x=-x;
}
template <typename T,typename ...Args>
inline void read(T &tmp,Args &...tmps){read(tmp);read(tmps...);}
const int N = 22 * 22 + 5;
int n,m,id[N][N],aa,b,d[N];
double a[N][N],p[N]; 
vector<int>g[N];
#define pb push_back 
signed main(){
    read(n,m,aa,b);
    rep(i,1,m){
        int u,v;
        read(u,v);    
        g[u].pb(v);
        g[v].pb(u);
        ++d[u],++d[v];
    }
    rep(i,1,n)scanf("%lf",&p[i]);
    m = 0;
    rep(i,1,n)rep(j,1,n)id[i][j] = ++m;
    a[id[aa][b]][m+1] = -1;//起点概率为1 
    rep(i,1,n)rep(j,1,n){
        int x = id[i][j];
        //f(i,j) = p[i] * p[j] * f[i][j]
        //f(i,j) * (p[i] * p[j] - 1) = 0
        //i == j不存在停留 
        a[x][x] --;
        if(i != j)a[x][x] += p[i] * p[j];
        for(int u : g[i])for(int v : g[j]){
            if(v == u)continue;
            a[x][id[u][v]] = (1 - p[u]) * (1 - p[v]) / d[u] / d[v];
        }//from(u,v) -> (i,j)
        for(int u : g[i]){
            if(u == j)continue;
            a[x][id[u][j]] = (1 - p[u]) * p[j] / d[u];
        }//from(u,j) -> (i,j)
        for(int u : g[j]){
            if(u == i)continue;
            a[x][id[i][u]] = (1 - p[u]) * p[i] / d[u];
        }//from(i,u) -> (i,j)
    }
    //gauss
    rep(i,1,m){//主元 
        int mx = i;
        rep(j,i+1,m){
            if(fabs(a[j][i]) > fabs(a[mx][i])){
                mx = j;
            }
        }
        rep(j,1,m+1)swap(a[i][j],a[mx][j]);
        rep(j,1,m){//
            if(j == i)continue;
            double K = a[j][i] / a[i][i];//系数 
            rep(k,i+1,m+1){
                a[j][k] -= a[i][k] * K;//减去 
            }
        }
    }
    rep(i,1,n)printf("%.10lf ", a[id[i][i]][m+1] / a[id[i][i]][id[i][i]]);
}

 

posted @ 2022-07-17 15:58  Xu_brezza  阅读(25)  评论(0编辑  收藏  举报