【xsy1201】 随机游走 高斯消元

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

数据范围:n10m1000

 

我们令 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)与边界相邻,但不在四个角,则把式子中的14改为13,并且将括号中的四个项删掉一个。

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

 

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

 

我们令x(i1)m+j来表示f[i][j]

那么式子就变成了xi=14(xi1+xi+1+xi+m+xim)+1

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

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

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

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

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

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

时间复杂度降低至O(n3m)。可以得到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 @   AlphaInf  阅读(510)  评论(3编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示