UVALive 4297 First Knight [期望+高斯消元(优化)]

  一个n*m的矩形,给出从每个点去它周围的四个点的概率,问从[1,1]走到[n,m]的所花步数期望是多少。

  在汤可因的国家集训队论文《浅析竞赛中一类数学期望问题的解决方法》中提到了这个题,对这种带环的模型一般都是高斯消元求解。

  假设从某个点走到终点所花步数的期望是d[i,j],很容易推出方程:

    

  这样对每个点列出一个方程,一共n*m个未知数,n*m个方程,用高斯消元即可求解,但是如果直接高斯消元复杂度会达到O(n^3*m^3),所以必然要在基础的高斯消元上加以优化。

  下面的这张图片取自题解,是当n=3,m=4时所列出的矩阵,题解中提到了一个block tridiagonal matrix,这应该是一种比较特殊的矩阵,暂且不管。

  

  观察这个矩阵,如果我们要把它化成上三角矩阵,对角线上全部都是1,对每个1,至多往下N个元素后,就全部是0了,所以至多只要对N行进行消元。而对每个1,消元的时候实际上都是参照这一行来消元的,而它的右边也至多也只有N个元素,后面就全部是0了,所以对于下面的每行,至多只要消N列就可以了,所以总的复杂度变为O(M*N^3)。另外建议在程序中从后向前把它化成下三角,这样最后就不用回代去求E11了。

  

 1 #include <string.h>
 2 #include <stdio.h>
 3 #define MAXN 1700
 4 double d[MAXN][MAXN],x;
 5 int an,am,n,m;
 6 void gauss(){
 7     int i=an,j=an;
 8     while(i>=1){
 9         for(int k1=i-1;k1>=i-1-m&&k1>=1;k1--){
10             double y=d[k1][j]/d[i][j];
11             for(int k2=j;k2>=j-m&&k2>=1;k2--)
12                 d[k1][k2]-=y*d[i][k2];
13             d[k1][am]-=y*d[i][am];
14         }
15         i--,j--;
16     }
17 }
18 int main(){
19     freopen("test.in","r",stdin);
20     while(scanf("%d%d",&n,&m),n||m){
21         an=n*m,am=an+1;
22         for(int i=1;i<=an;i++)for(int j=1;j<=an;j++)d[i][j]=0;
23         for(int k=0;k<4;k++){
24             for(int i=1;i<=n;i++){
25                 for(int j=1;j<=m;j++){
26                     scanf("%lf",&x);
27                     int pos=i*m+j-m;
28                     if(k==0)d[pos][pos]=-1;
29                     if(k==0&&i<n)d[pos][pos+m]=x;
30                     else if(k==1&&j<m)d[pos][pos+1]=x;
31                     else if(k==2&&i>1)d[pos][pos-m]=x;
32                     else if(k==3&&j>1)d[pos][pos-1]=x;
33                 }
34             }
35         }
36         for(int i=1;i<=an;i++)d[i][am]=-1;d[an][am]=0;
37         gauss();
38         printf("%.6f\n",d[1][am]/d[1][1]);
39     }
40     return 0;
41 }

 

  

posted @ 2012-09-01 08:55  Burn_E  阅读(638)  评论(0编辑  收藏  举报