列出$n imes m$个未知量、$n imes m$个方程的方程组进行高斯消元。
注意到每次消元时只会影响前后$m$个方程,故只保存增广矩阵中的这些项,同时只对这些项进行消元即可。
时间复杂度$O(nm^3)$。
#include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int N=10010,M=23; const double eps=1e-12; int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1}; int n,m,i,j,k,x,y,o,l,r,cnt,pos[N*M],v[N*M]; double p[4],t,a[N*M][M*2],g[N*M]; char s[N][M]; inline double&f(int x,int y){return a[x][x-y+M];} int main(){ scanf("%d%d",&m,&n); for(i=0;i<4;i++)scanf("%lf",&p[i]),p[i]/=100; for(i=0;i<n;i++)scanf("%s",s[i]); for(i=0;i<m;i++)if(s[0][i]=='.')cnt++; for(i=0;i<n;i++)for(j=0;j<m;j++)if(s[i][j]!='X'){ o=i*m+j; f(o,o)=1; if(!i)g[o]=1.0/cnt; for(k=0;k<4;k++){ x=i+dx[k],y=j+dy[k]; if(x<0||x>=n||y<0||y>=m||s[x][y]=='X')f(o,o)-=p[k]; else if(s[x][y]=='.')f(o,x*m+y)-=p[k^1]; } if(s[i][j]=='T')f(o,o)=1; } for(i=0;i<n*m;i++){ l=max(0,i-m),r=min(n*m-1,i+m),k=-1; for(j=l;j<=r;j++)if(!v[j])if(fabs(f(j,i))>eps){k=j;break;} if(k<0){pos[i]=-1;continue;} v[pos[i]=k]=1; for(j=k+1;j<=r;j++){ t=f(j,i)/f(k,i); for(x=i;x<n*m&&x<=k+m;x++)f(j,x)-=f(k,x)*t; g[j]-=g[k]*t; } } for(i=n*m-1;~i;i--)if(~pos[i]){ k=pos[i],l=max(0,i-m),r=min(n*m-1,i+m); for(j=l;j<=r;j++)if(j!=k)g[k]-=f(k,j)*g[j]; g[k]/=f(k,i); } for(i=0;i<n;i++)for(j=0;j<m;j++)if(s[i][j]=='T')printf("%.9f ",g[pos[i*m+j]]); return 0; }