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;
}
posted @ 2017-06-29 21:14  Monster_Yi  阅读(392)  评论(0编辑  收藏  举报