NXM 矩阵的所有 AXB 子矩阵中的最大元素

Posted

技术标签:

【中文标题】NXM 矩阵的所有 AXB 子矩阵中的最大元素【英文标题】:Maximum element in all AXB sub matrices of NXM matrix 【发布时间】:2016-06-10 17:46:00 【问题描述】:

我试图从矩阵 NXM 中找到任何子矩阵 AXB 的最大元素。我实现了稀疏树方法。但是我无法对此进行优化。其实我需要解决范围查询,所以我需要优化代码。在进行预计算时,对于任何 N,M 值,它需要 O(NMlog(N)log(M)) 时间复杂度。我怎样才能将其改进为(N * M)。这是我的预计算代码

for(int i=0; i<n;i++)
  for(int j=0; j<m;j++)
        cin>>arr[i][j];

for(int i=0; pow(2,i) <= n; i++)
        for(int j=0; pow(2,j) <= m; j++)
            for(int x=0; x + pow(2,i)-1 < n; x++)
                for(int y = 0; y + pow(2,j) -1 < m; y++)
                
                    i=(int)i;
                    j=(int)j;
                    if (i == 0 && j == 0)
                            M[x][y][i][j] = arr[x][y]; 
                    else if (i == 0)
                            M[x][y][i][j] = maxi(2,M[x][y][i][j-1], M[x][(int)(y+pow(2,(j-1)))][i][j-1]);
                    else if (j == 0)
                            M[x][y][i][j] = maxi(2,M[x][y][i-1][j], M[(int)(x+ pow(2,(i-1)))][y][i-1][j]);
                    else 
                            M[x][y][i][j] = maxi(4,M[x][y][i-1][j-1], M[(int)(x + pow(2,(i-1)))][y][i-1][j-1], M[x][(int)(y+pow(2,(j-1)))][i-1][j-1], M[(int)(x + pow(2,(i-1)))][(int)(y+pow(2,(j-1)))][i-1][j-1]);
                

对于输入 x,y,x1,y1

 k = log(x1 - x + 1);
 l = log(y1 - y + 1);
 int max_element = max(4,M[x][y][k][l], M[(int)(x1 - pow(2,k) + 1)][y][k][l], M[x][(int)(y1 - pow(2,l) + 1)][k][l], M[(int)(x1 - pow(2,k) + 1)][(int)(y1 - pow(2,l) + 1)][k][l]);

如何提高此代码的性能。请帮忙。

【问题讨论】:

【参考方案1】:

这个方案不比O(N*M*Log(N)*Log(M))好,但比你的实现好。

通过查看你的for循环的执行顺序和数组M的访问顺序,会有太多的内存跳转和缓存未命中导致程序运行缓慢。

例子:-

查看以下循环所花费的时间:

int M[1000][1000][11][11];
for(int i = 0 ; i <= 10 ; i++)
    for(int j = 0 ; j <= 10 ; j++)
        for(int x = 0 ; x < 1000 ; x++)
            for(int y = 0 ;  y < 1000 ; y++)
                M[x][y][i][j] = 1;
            
        
    

执行需要 1.9 秒

int M[11][11][1000][1000];
for(int i = 0 ; i <= 10 ; i++)
    for(int j = 0 ; j <= 10 ; j++)
        for(int x = 0 ; x < 1000 ; x++)
            for(int y = 0 ;  y < 1000 ; y++)
                M[i][j][x][y] = 1;
            
        
    

而这个只需要 0.2 秒。因此,请始终尝试编写循环,以便对内存进行顺序访问。

更多详情可以阅读here。

因此,如果您按以下方式更改代码,速度会更快:

M[Log(n)][Log(m)][n][m];
for(int i=0; (1<<i) <= n; i++)
        for(int j=0; (1<<j) <= m; j++)
            for(int x=0; x + (1<<i)-1 < n; x++)
                for(int y = 0; y + (1<<j) -1 < m; y++)
                
                    i=(int)i;
                    j=(int)j;
                    if (i == 0 && j == 0)
                            M[i][j][x][y] = arr[x][y]; 
                    else if (i == 0)
                            M[i][j][x][y] = maxi(2,M[i][j-1][x][y], M[i][j-1][x][(y+(1<<(j-1)))]);
                    else if (j == 0)
                            M[i][j][x][y] = maxi(2,M[i-1][j][x][y], M[i-1][j][(x+ (1<<(i-1)))][y]);
                    else 
                            M[i][j][x][y] = maxi(4,M[i-1][j-1][x][y], M[i-1][j-1][(x + (1<<(i-1)))][y], M[i-1][j-1][x][(y+(1<<(j-1)))], M[i-1][j-1][(x + (1<<(i-1)))][(y+(1<<(j-1)))]);
                

如果您计算 log() 的次数过多(即 10^5 或更大的顺序),则可以再进行一项优化,而不是使用 31-__builtin_clz() 而不是 log()

k = 31-__builtin_clz(x1 - x + 1);
l = 31-__builtin_clz(y1 - y + 1);
int max_element = max(4,M[k][l][x][y], M[k][l][(x1 - (1<<k) + 1)][y], M[k][l][x][(y1 - (1<<l) + 1)], M[k][l][(x1 - (1<<k) + 1)][(y1 - (1<<l) + 1)]);

【讨论】:

谢谢,但您修改的算法对每个 x,y,x1,y1 给出了错误的答案。同样在此操作之后,我的数组正在改变。为什么会这样? 我没有改变你的算法。我只是更改了数组元素的访问,以便它可以更快。不要复制粘贴此代码,这可能会出错。 我已经实现了您在***.com/questions/37627085/… 链接中指定的内容。这是我的代码ideone.com/ntfXKB 的链接。你能告诉我哪里错了吗? 您在编辑之前复制了错误的代码。现在只需使用上面的新代码,这将给出正确的输出。 感谢您指出我的错误。但是当情况是 x1=1, y1=3, x2=1, y2= 4 时它会失败。给定矩阵的输出应该是 4 但它给出的是 3。

以上是关于NXM 矩阵的所有 AXB 子矩阵中的最大元素的主要内容,如果未能解决你的问题,请参考以下文章

HihoCoder 1502 : 最大子矩阵 (双指针)

[Offer收割]编程练习赛13 B.最大子矩阵[枚举]

01矩阵求最大子矩阵大小

hihocoder 1580 dp最大子矩阵和

较大矩阵中的最大相等子矩阵

动态规划-最大子矩阵