BZOJ4079 [Wf2014]Pachinko
完整题面:
设f(i,j)表示路径经过(i,j)这个点的概率,列出方程消元。
但暴力消元的复杂度是$O((nm)^3)$,注意每一次消元只会影响前后m个方程,所以我们可以对于第i行,只存[i-m,i+m]这些系数来进行消元。
时间复杂度$O(nm^3)$
姿势水平UP~
(代码基本抄Claris的)
#include <cstdio> #include <cmath> #include <algorithm> using namespace std; #define f(x,y) a[x][y-x+m] #define eps 1e-12 const int N=10005,M=25,dx[]={-1,1,0,0},dy[]={0,0,-1,1}; char s[N][M]; int n,m,tt,p[N*M],v[N*M]; double d[4],a[N*M][M*2],g[N*M]; int main() { scanf("%d%d",&m,&n); for(int i=0;i<4;i++) scanf("%lf",&d[i]),d[i]/=100; for(int i=0;i<n;i++) scanf("%s",s[i]); for(int i=0;i<m;i++) if(s[0][i]=='.') tt++; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(s[i][j]!='X') { int o=i*m+j,x,y; f(o,o)=1; if(!i) g[o]=1./tt; for(int 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)-=d[k]; else if(s[x][y]=='.') f(o,x*m+y)-=d[k^1]; } if(s[i][j]=='T') f(o,o)=1; } for(int i=0;i<n*m;i++) { int l=max(0,i-m),r=min(n*m-1,i+m),k=-1; for(int j=l;j<=r;j++) if(!v[j]&&fabs(f(j,i))>eps) {k=j; break;} p[i]=k; if(~k) v[k]=1; else continue; for(int j=k+1,x;j<=r;j++) { double 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(int i=n*m-1;~i;i--) if(~p[i]) { int k=p[i],l=max(0,i-m),r=min(n*m-1,i+m); for(int j=l;j<=r;j++) if(j^k) g[k]-=f(k,j)*g[j]; g[k]/=f(k,i); } for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(s[i][j]=='T') printf("%.9f\n",g[p[i*m+j]]); return 0; }