[BZOJ3270][高斯消元][概率与期望]博物馆

f(x,y) 为一个人在x一个人在y的概率(与f(y,x)不同)

有四种转移
f(x,y)p[x]p[y]f(x,y)

f(x,y)p[x](1p[y])/d[y]f(x,v) v 为与 y 相连的房间

f(x,y)(1p[x])p[y]/d[x]f(u,y) u 为与 x 相连的房间

f(x,y)(1p[x])(1p[y])/d[x]/d[y]f(u,v)

可以列出方程组

a11f(x1,y1)+a12f(x2,y2)+...+a1nf(xn,yn)=f(u1,v1)a21f(x1,y1)+a22f(x2,y2)+...+a2nf(xn,yn)=f(u2,v2)...a31f(x1,y1)+a32f(x2,y2)+...+a3nf(xn,yn)=f(u3,v3)

用高斯消元解出答案

#include 
#include 
#include 
#include 
#include 
#define eps 1e-7
#define g(a,b) ((a-1)*n+b)

using namespace std;

int n,m,a,b,cnt,u,v,t,w,tot;
int d[25];
double A[410][410];
double p[25];
vector<int> E[25];

inline void Insert(int u,int v){
    E[u].push_back(v); E[v].push_back(u);
    d[u]++; d[v]++;
}

inline void check(int x,int y){
    double *B=A[g(x,y)];
    B[g(x,y)]=-1;
    for(int i=0;i<(int)E[x].size();i++)
        for(int j=0;j<(int)E[y].size();j++){
            u=E[x][i]; v=E[y][j]; w=g(u,v);
            if(u!=v){
                if(u==x&&v==y) B[w]+=p[u]*p[v];
                else if(u==x) B[w]+=p[u]*(1-p[v])/d[v];
                else if(v==y) B[w]+=p[v]*(1-p[u])/d[u];
                else B[w]+=(1-p[u])*(1-p[v])/d[v]/d[u];
            }
        }
}

inline void gauss(){
    int now=1;
    for(int i=1,j,k;i<=tot;i++){
        for(j=now;j<=tot&&fabs(A[j][i])if(j>tot) continue;
        if(j!=now) for(k=1;k<=tot+1;k++) swap(A[j][k],A[now][k]);
        double t=A[now][i];
        for(j=1;j<=tot+1;j++) A[now][j]/=t;
        for(j=1;j<=tot;j++)
            if(j!=now){
                t=A[j][i];
                for(k=1;k<=tot+1;k++) A[j][k]-=t*A[now][k];
            }
        now++;
    }
}

int main(){
    scanf("%d%d%d%d",&n,&m,&a,&b);
    tot=n*n;
    A[g(a,b)][tot+1]=-1;
    for(int i=1;i<=n;i++) E[i].push_back(i);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        Insert(u,v);
    }
    for(int i=1;i<=n;i++) scanf("%lf",&p[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        check(i,j);
    gauss();
    for(int i=1;i<=n;i++) printf("%.6lf ",A[g(i,i)][tot+1]);
}

你可能感兴趣的:(概率与期望,高斯消元)