BZOJ4079 : [Wf2014]Pachinko

列出$n\times m$个未知量、$n\times 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\n",g[pos[i*m+j]]);
  return 0;
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值