高斯消元|随机游走 模板

高斯消元

时间复杂度:\(O(n^3)\)

/*
n行:[0,n)
m列:[0,m)
m=2n时,右侧矩阵是左侧矩阵的逆
m=n+1时,右侧一列是左侧方程组的解
*/

//double
double a[][];
bool gauss(int n,int m){
    for(int i=0,r=0;i<n;r=++i){
        for(int j=i+1;j<m;++j)if(abs(a[j][i])>abs(a[r][i]))r=j;
        if(i^r)for(int j=0;j<m;++j)swap(a[i][j],a[r][j]);
        if(abs(a[i][i]-1)<1e-10)return 0;//矩阵非奇异或方程组无解
        double b=a[i][i];
        for(int j=i;j<m;++j)a[i][j]=a[i][j]/b;
        for(int k=0;k<n;++k){
            if(k==i)continue;
            double p=a[k][i];
            for(int j=i;j<m;++j)a[k][j]-=p*a[i][j];
        }
    }
    return 1;
}

//模mod下的解
ll a[][];
bool gauss(int n,int m){
    for(int i=0,r=1;i<n;r=++i){
        for(int j=i+1;j<n;++j)if(a[j][i]>a[r][i])r=j;
        if(i^r)for(int j=0;j<m;++j)swap(a[i][j],a[r][j]);
        if(a[i][i]==0)return 0;//矩阵非奇异或方程组无解
        ll b=qpow(a[i][i],mod-2);
        for(int j=i;j<n;++j)a[i][j]=a[i][j]*b%mod;
        for(int k=0;k<n;++k){//第k行
            if(k==i)continue;
            ll p=a[k][i];
            for(int j=i;j<m;++j)a[k][j]=(a[k][j]-p*a[i][j]%mod+mod)%mod;
        }
    }
    return 1;
}
  • 随机游走

\(p(k,x)\)为经过\(k(k\ge 0)\)步到达x的概率
令:\(P(x)=\sum_{k=0}^{+\infty}p(k,x)\\ e(k,x)=k\cdot p(k,x)\\ E(x)=\sum_{k=1}^{+\infty}e(k,x)=\sum_{k=1}^{+\infty}k\cdot p(k,x)\)

到达终点的期望步数\(ans= \frac{E(x)}{P(x)}\)
设:
集合\(S(x)=\{y|y通过某条边可以到达x\}\)
out(x)为点x的出度(终点出度为0,即与终点连接的都是单向边)
有下列两个等式:

  1. \(p(k,x)=\sum_{y\in S(x)}\frac{p(k-1,y)}{out(y)},k\ge 1\)且y不能是终点
  2. \(\frac{e(k,x)}{k}=\sum_{y\in S(x)}\frac{e(k-1,y)}{(k-1)out(y)},k\ge 2\)且y不能是终点

等式1,k从1累加到\(+\infty\)
\(p(k,x)=\sum_{y\in S(x)}\frac{p(k-1,y)}{out(y)}\)

\(\Rightarrow\sum_{k=1}^{+\infty}p(k,x)=\sum_{y\in S(x)}\frac{1}{out(y)}\left(\sum_{k=1}^{+\infty}p(k-1,y)\right)\)

\(\Rightarrow P(x)-p(0,x)=\sum_{y\in S(x)}\frac{1}{out(y)}P(y)\)

\(\Rightarrow P(x)-\sum_{y\in S(x)}\frac{1}{out(y)}P(y)=p(0,x)\)

等式2,k从2累加到\(+\infty\)

\(\frac{e(k,x)}{k}=\sum_{y\in S(x)}\frac{e(k-1,y)}{(k-1)out(y)}\)

\(\Rightarrow\sum_{k=2}^{+\infty}\frac{e(k,x)}{k}=\sum_{y\in S(x)}\frac{1}{out(y)}\sum_{k=2}^{+\infty}\frac{e(k-1,y)}{k-1}\)

\(\Rightarrow\sum_{k=2}^{+\infty}e(k,x)=\sum_{y\in S(x)}\frac{1}{out(y)}\sum_{k=2}^{+\infty}\left(1+\frac{1}{k-1}\right)\cdot e(k-1,y)\)

\(\Rightarrow E(x)-e(1,x)=\sum_{y\in S(x)}\frac{1}{out(y)}\left(E(y)+\sum_{k=2}^{+\infty}p(k-1,y)\right)\)

\(\Rightarrow E(x)-e(1,x)=\sum_{y\in S(x)}\frac{1}{out(y)}\left(E(y)+P(y)-p(0,y)\right)\)

\(\Rightarrow E(x)-\sum_{y\in S(x)}\frac{E(y)}{out(y)}=\sum_{y\in S(x)}\frac{P(y)-p(0,y)}{out(y)}+p(1,x)\)

给定一个没有自环的简单图,从0点出发,求到n-1点的期望步数.

double P[],p0[];
//分别是P(x)和p(0,x)
int main(){
    read(n,m);//n个点,m条边
    for(int i=0,x,y;i<m;++i){
        read(x,y);//xy之间有一条边.
        //终点n-1只有入度,没有出度.
        if(x!=n-1){
            mp[x][y]=1,out[x]++;
        }
        if(y!=n-1){
            mp[y][x]=1,out[y]++;
        }
    }
    p0[0]=1;//只有这一个是1,其余全为零
    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            if(mp[j][i]==0)continue;
            a[i][j]=-1.0/(double)s[j];
        }
        a[i][i]=1;
        a[i][n]=p0[i];
    }
    gauss(n,n+1);//求得p(x)
    for(int i=0;i<=n;++i)p[i]=a[i][n];
    for(int i=0;i<n;++i)for(int j=0;j<=n;++j)a[i][j]=0;
    for(int i=0;i<n;++i){
        double tot=0;
        for(int j=0;j<n;++j){
            if(mp[j][i]==0)continue;
            a[i][j]=-1.0/(double)s[j];
            tot+=(p[j]-p0[j])/(double)s[j];
        }
        a[i][i]=1;
        if(mp[0][i])tot+=1.0/(double)s[0];//与起点相邻的点p(1,x)才不为零
        a[i][n]=tot;
    }
    gauss(n,n+1);
    printf("%.5f",a[n-1][n]/p[n-1]);
    return 0;
}

posted @ 2020-12-18 17:03  肆之月  阅读(133)  评论(0编辑  收藏  举报