zoukankan      html  css  js  c++  java
  • 【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
    "); 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
    ",ans);
    49 }
    50 
    51 int main(){
    52     int cas; cin>>cas;
    53     while(cas--) Main();
    54 }
  • 相关阅读:
    React使用iconfont图标下载到本地symbol引用
    【汇编】求100以内的素数asm
    jQuery Ajax.BeginForm方法回调函数高版本3.3.1不兼容问题
    python中的深拷贝与浅拷贝
    闲来无事做个C#小项目——2
    C#使用MD5加密
    数据结构部分总结(c语言版)
    vue 上传视频和图片 并且截取视频第一帧作为播放前默认图片
    vue el-cascader取id和lable的值
    C# 枚举的定义,枚举的用法,获取枚举值
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9381401.html
Copyright © 2011-2022 走看看