【xsy1201】 随机游走 高斯消元

题目大意:你有一个$n*m$的网格(有边界),你从$(1,1)$开始随机游走,求走到$(n,m)$的期望步数。

数据范围:$n≤10$,$m≤1000$。

 

我们令 $f[i][j]$表示从$(1,1)$随机游走到$(i,j)$的期望步数。不难推出:

如果$(i,j)$与边界不想邻,则有 $f[i][j]=\frac{1}{4}(f[i-1][j]+f[i+1][j]+f[i][j-1]+f[i][j+1])+1$

如果$(i,j)$与边界相邻,但不在四个角,则把式子中的$\frac{1}{4}$改为$\frac{1}{3}$,并且将括号中的四个项删掉一个。

如果$(i,j)$在非起点的三个角上,则式子也显然。

 

显然这是一个$nm$元一次方程,我们可以考虑用高斯消元在$O(n^3m^3)$的时间内完成求解,这样子可以拿到$50$分的好成绩。

 

我们令$x_{(i-1)m+j}$来表示$f[i][j]$。

那么式子就变成了$x_i=\frac{1}{4}(x_{i-1}+x_{i+1}+x_{i+m}+x_{i-m})+1$

然后我们会发现,第$i$条式子只有$[i-m,i+m]$是有值的。

根据高斯消元的特征,第i条式子中包含$x_{[i-m,i)}$的项值会被消掉,那么实际上存在项的部分为$x_{[m,i+m]}$。

我们又发现,式子中包含$x_i$的,只可能第$i-m$条式子至第$i+m$条式子。

那么,我们在高斯消元时,并不需要把对所有式子进行处理,只需要处理第$i$条式子的后$m$条式子的第$i$项至第$i+m$项即可。

时间复杂度降低至$O(nm^3)$,你可以得到$80$分的好成绩。

考虑到$m$很大,依然无法求解,考虑到$n$很小,我们将$n$和$m$进行$swap$,然后再去求解即可。

时间复杂度降低至$O(n^3m)$。可以得到$100$分的好成绩。

 

 1 #include<bits/stdc++.h>
 2 #define M 10005
 3 #define ok(x,y) (1<=(x)&&(x)<=n&&1<=(y)&&(y)<=m)
 4 #define ok2(x,y) (ok(x,y)&&(!(x==1&&y==1)))
 5 #define D double
 6 using namespace std;
 7 
 8 D *a[M];int n,m;
 9 
10 D get(int i,int j){
11     D hh=0;
12     if(ok(i-1,j)) hh++;
13     if(ok(i+1,j)) hh++;
14     if(ok(i,j+1)) hh++;
15     if(ok(i,j-1)) hh++;
16     return 1/hh;
17 }
18 
19 void newhh(int x){
20     int i=(x-1)/m+1,j=(x-1)%m+1;
21     a[x]=new D[n*m+2];
22     memset(a[x],0,sizeof(D)*(n*m+2));
23     D hh=get(i,j);
24     if(ok2(i-1,j)) a[x][x-m]=-hh;
25     if(ok2(i+1,j)) a[x][x+m]=-hh;
26     if(ok2(i,j+1)) a[x][x+1]=-hh;
27     if(ok2(i,j-1)) a[x][x-1]=-hh;
28     a[x][x]=1; a[x][n*m+1]=1;
29 }
30 
31 int Main(){
32     scanf("%d%d",&n,&m);
33     if(n==1&&m==1) {printf("0\n"); return 0;}
34     if(m>n) swap(n,m);
35     for(int i=2;i<=m+2;i++) newhh(i);
36     for(int i=2;i<n*m;i++){
37         for(int j=i+1;j<=min(i+m,n*m);j++){
38             D hh=a[j][i]/a[i][i];
39             for(int k=i;k<=min(i+m,n*m);k++)
40             a[j][k]-=hh*a[i][k];
41             a[j][n*m+1]-=hh*a[i][n*m+1];
42         }
43         delete[] a[i];
44         if(i+m+1<=n*m) newhh(i+m+1);
45     }
46     D ans=a[n*m][n*m+1]/a[n*m][n*m];
47     delete[] a[n*m];
48     printf("%.0lf\n",ans);
49 }
50 
51 int main(){
52     int cas; cin>>cas;
53     while(cas--) Main();
54 }

 

posted @ 2018-07-28 11:41  AlphaInf  阅读(502)  评论(3编辑  收藏  举报