高斯消元|随机游走 模板
高斯消元
时间复杂度:\(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,即与终点连接的都是单向边)
有下列两个等式:
- \(p(k,x)=\sum_{y\in S(x)}\frac{p(k-1,y)}{out(y)},k\ge 1\)且y不能是终点
- \(\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;
}