[bzoj3317]First Knight
建立方程后直接高斯消元,再把0的区间找出来计算,就可以过(因为实际上这样的复杂度是5次的,且常数小)
(当然这样的复杂度看上去并不太好,考虑优化)
可以发现最后一行的概率都可以用上一行来表示,那么代入上一行的方程后,发现又可以再次代入,最后就求出了第一行
1 #include<bits/stdc++.h> 2 using namespace std; 3 int t,n,m,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1}; 4 double f[2005][2005]; 5 int id(int x,int y){ 6 if ((x<1)||(y<1)||(x>n)||(y>m))return 0; 7 return (x-1)*m+y; 8 } 9 double guess(){ 10 for(int ii=n;ii;ii--){ 11 for(int i=id(ii,1);i<=id(ii,m);i++){ 12 double s=abs(f[i][i]); 13 for(int j=i+1;j<=id(ii,m);j++)s=max(s,abs(f[j][i])); 14 for(int j=i;j<=id(ii,m);j++) 15 if (s==abs(f[j][i])){ 16 s=f[j][i]; 17 for(int k=id(ii-1,1);k<=id(ii,m);k++)swap(f[j][k],f[i][k]); 18 swap(f[j][id(n,m)+1],f[i][id(n,m)+1]); 19 break; 20 } 21 for(int j=id(ii-1,1);j<=id(ii,m);j++)f[i][j]/=s; 22 f[i][id(n,m)+1]/=s; 23 for(int j=id(ii,1);j<=id(ii,m);j++){ 24 if (j==i)continue; 25 s=f[j][i]; 26 for(int k=id(ii-1,1);k<=id(ii,m);k++)f[j][k]-=f[i][k]*s; 27 f[j][id(n,m)+1]-=f[i][id(n,m)+1]*s; 28 } 29 } 30 if (ii==1)return f[1][id(n,m)+1]; 31 for(int i=id(ii-1,1);i<=id(ii-1,m);i++) 32 for(int j=id(ii,1);j<=id(ii,m);j++){ 33 for(int k=id(ii-1,1);k<=id(ii-1,m);k++)f[i][k]-=f[i][j]*f[j][k]; 34 f[i][id(n,m)+1]-=f[i][j]*f[j][id(n,m)+1]; 35 } 36 } 37 } 38 int main(){ 39 while (scanf("%d%d",&n,&m)!=EOF){ 40 if ((!n)&&(!m))return 0; 41 memset(f,0,sizeof(f)); 42 for(int i=1;i<=n;i++) 43 for(int j=1;j<=m;j++) 44 f[id(i,j)][id(i,j)]=f[id(i,j)][id(n,m)+1]=-1; 45 for(int k=0;k<4;k++) 46 for(int i=1;i<=n;i++) 47 for(int j=1;j<=m;j++) 48 scanf("%lf",&f[id(i,j)][id(i+dx[k],j+dy[k])]); 49 f[id(n,m)][id(n,m)+1]=0; 50 printf("%.8f\n",guess()); 51 } 52 }