1

输入是一个数组(n*m 1<n,m< 1000)。我必须在 的每个子矩阵中找到最大元素size( a*b )

我试图通过x一遍n-a+1又一y遍地迭代来做到这一点m-j+1

  • 2D segment treesor quad trees不够快,因为查询的数量很大。
  • 我试图扩展sparse table,但由于空间不足而无法扩展。

  • 我已经阅读了有关解决方案的信息,Cartesian trees但是由于我无法理解,因此需要一些代码。

请解释一个将通过预计算O(nm)及时或及时回答查询的解决方案。O(1)此外,输入数组是静态的。

注意:虽然我试过sparse table了,但它可能不正确,所以请随时发布解决方案。

我是一名Java编码员,所以实现Javac/c++将是伟大的。

这也不是重复的,因为我已经搜索了很多关于它没有找到任何合适的东西。

4

2 回答 2

2

可能性的数量:

(来自大小为 MxN 的矩阵中大小为 AxB 的子矩阵的数量
在 的矩阵中size (m*n),有 的(n-A+1)*(m-B+1)不同矩阵size (A*B)
因此,您的函数可能输入的总数是sum((n-A+1)*(m-B+1))whereA=1..nB=1..m

编辑:当 m=1000 时,这变得如此巨大。

O(m^2n^2)O(1000^4)... 1 万亿... 这不适合我的小型计算机的内存 :)

结构:

我建议您构建一个hashmap您只需使用矩阵边界进行索引的字符串:
A string built from a=M(i,j), b=M(k,l)where0< i < k <(n+1)0< j < l <(m+1)

  • 例如,您可以构建是这样的:aHashMap("["+i+","+j+"].["+k+","+l+"]")

预计算:

  • 有一个函数可以计算给定矩阵的最大值 (a[i,j],b[k,l]) - 比如说myMax(i,j,k,l)。我认为没有必要告诉你怎么做。

  • 然后它很容易(对不起,我不能轻易编译任何东西,所以我现在只给出原理):

    对于 i=1 到 n-1 做
        对于 j=1 到 m-1 做
            对于 k=i 到 n 做
                对于 l=j 到 m 做
                    aHashMap("["+i+","+j+"].["+k+","+l+"]") = myMax(i,j,k,l)
                下一个
            下一个
        下一个
    下一个
    

这是O(n^4),但假设它是预先计算的,没有意义,它只会让你的程序在存储时越来越大aHashMap

很高兴知道

这样的问题似乎也在http://cs.stackexchange.com得到了广泛的解决;例如这个那个......所以这个SE可能对OP感兴趣。

这种幼稚方法的实现:

有了99 x 95它已经提供了数百万种预先计算的可能性,大约需要 3Go RAM!

$ ./p1
 enter number of rows:99
 enter number of cols:95
pre-computing...
hashmap ready with 22572000 entries.

矩阵.h

#ifndef myMatrix_JCHO
#define myMatrix_JCHO

typedef unsigned int u_it;

class Matrix
{
public:
    Matrix(u_it _n, u_it _m);
    Matrix(const Matrix& matr);
    Matrix& operator=(const Matrix& matr);
    ~Matrix();

    u_it getNumRows() ;
    u_it getNumCols() ;

    int getC(u_it i, u_it j);
    void setC(u_it i, u_it j, int v);
    void printMatrix();
    int maxSub(u_it a_i, u_it a_j, u_it b_k, u_it b_l);

private:
    u_it n, m;
    int **pC;

};

#endif

矩阵.cpp

#include <iostream>
#include <string>
#include <sstream>

#include "matrix.h"

Matrix::Matrix(u_it _n, u_it _m) {
    n=_n;
    m=_m;
    int k=0;
    pC = new int*[n];
    for (u_it i=0; i<n; ++i){
       pC[i]=new int[m];
       for(u_it j=0; j<m; ++j){
         pC[i][j]=++k;
       }
    }
}
Matrix::~Matrix(){
    for (u_it i=0; i<n; ++i){
        delete [] pC[i];
    }
    delete [] pC;
    std::cout << "matrix destroyed\n";
}
u_it Matrix::getNumRows() {
    return n;
}
u_it Matrix::getNumCols() {
    return m;
}
int Matrix::getC(u_it i, u_it j){
    return pC[i][j];
}
void Matrix::setC(u_it i, u_it j, int v){
    pC[i][j]=v;
}
void Matrix::printMatrix(){
    for (u_it i=0; i<n; ++i){
      std::cout << "row " <<i<<" [ ";
      for(u_it j=0; j<m; ++j){
        std::cout << pC[i][j] << '\t';
      }
      std::cout << "]\n";
    }
}

// Return max of submatrix a(i,j); b(k,l)
int Matrix::maxSub(u_it a_i, u_it a_j, u_it b_k, u_it b_l) {
   int res = -100000;
   if (a_i<=b_k && a_j<=b_l && b_k<n && b_l<m) {
     for (u_it i=a_i; i<=b_k; ++i){
       for(u_it j=a_j; j<=b_l; ++j){
         res= (pC[i][j]>res)? pC[i][j] : res;
       }
     }
   } else {
     std::cout << "invalid arguments: out of bounds\n";
     return -100000;
   }

   return res;
}

主文件

#include <iostream>
#include <string>
#include <sstream>
#include <map>
#include <cassert>

#include "matrix.h"

std::string hashKey(u_it a_i, u_it a_j, u_it b_k, u_it b_l) {
    std::stringstream ss;
    ss << "max(a[" << a_i << "," << a_j << "],b[" << b_k << "," << b_l << "]";
    return ss.str();
}

int main() {
    u_it n_rows, n_cols;
    std::cout << " enter number of rows:";
    std::cin >> n_rows;
    std::cout << " enter number of cols:";
    std::cin >> n_cols;
    std::cout << " pre-computing...\n";

    std::map<std::string, int> myHMap;
    Matrix * mat=new Matrix(n_rows,n_cols);
    //mat->printMatrix();
    // "PRE" computation
    for (u_it i=0; i<n_rows; ++i) {
      for (u_it j=0; j<n_cols; ++j) {
        for (u_it k=i; k<n_rows; ++k) {
          for (u_it l=j; l<n_cols; ++l) {
            //std::cout <<"max(a["<<i<<","<<j<<"],b["<<k<<","<<l<<"]"<< mat->maxSub(i, j, k, l) <<'\n';
            //std::cout << mat->hashKey(i, j, k ,l) <<" -> " <<  mat->maxSub(i, j, k, l)  <<'\n';
            myHMap[hashKey(i, j, k ,l)] = mat->maxSub(i, j, k, l);
          }
        }
      }
    }
    std::cout << " hashmap ready with "<<  myHMap.size() <<" entries.\n";
    // call to values
    u_it cw_i, cw_j, cw_k, cw_l;
    cw_i=0;
    std::string hKey;
    while (cw_i < n_rows+1) {
      std::cout << " enter i,:";
      std::cin >> cw_i;
      std::cout << " enter j,:";
      std::cin >> cw_j;
      std::cout << " enter k,:";
      std::cin >> cw_k;
      std::cout << " enter l:";
      std::cin >> cw_l;
      hKey = hashKey(cw_i, cw_j, cw_k, cw_l);
      std::map<std::string, int>::iterator i = myHMap.find(hKey);
      assert(i != myHMap.end());
      std::cout << i->first <<" -> " <<  i->second  <<'\n';
    }
}

制作

g++ -std=c++0x  -std=c++0x -Wall -c -g matrix.cpp
g++ -std=c++0x  -std=c++0x -Wall -c -g main.cpp
g++ -std=c++0x  -std=c++0x -Wall -g matrix.o main.o -o p1
于 2016-06-09T12:56:28.943 回答
0

我找到了让它计算的答案O(mn)——仍然需要一点预计算——但这次最后一个也很容易O(mn.log(mn)):它只是对所有矩阵值的列表进行排序。

预计算:

第一步是简单地构建矩阵值的有序结构,例如M(A),然后使用<algorithm>std::sort对该结构进行排序。

检索任何子矩阵的最大值(a,b)

要获得任何矩阵的最大值,只需从预先计算的结构中的最大值开始,M(A)并检查它是否在(a,b).

  • 如果是,那么你就完成了
  • 否则,拿下一个M(A)

矩阵.h

#ifndef myMatrix_JCHO
#define myMatrix_JCHO

typedef unsigned int u_it;
typedef std::pair<u_it, u_it> uup;

class Matrix
{
public:
    Matrix(u_it _n, u_it _m);
    Matrix(const Matrix& matr);
    Matrix& operator=(const Matrix& matr);
    ~Matrix();

    u_it getNumRows() ;
    u_it getNumCols() ;

    int getC(u_it i, u_it j);
    void setC(u_it i, u_it j, int v);
    void printMatrix();
    int maxSub(u_it a_i, u_it a_j, u_it b_k, u_it b_l);

private:
    u_it n, m;
    int **pC;

};

#endif

矩阵.cpp

#include <iostream>
#include <string>
#include <sstream>

#include "matrix.h"

Matrix::Matrix(u_it _n, u_it _m) {
    n=_n;
    m=_m;
    //int k=0;
    pC = new int*[n];
    for (u_it i=0; i<n; ++i){
       pC[i]=new int[m];
       for(u_it j=0; j<m; ++j){
         pC[i][j]=rand()%1000;
       }
    }
}
Matrix::~Matrix(){
    for (u_it i=0; i<n; ++i){
        delete [] pC[i];
    }
    delete [] pC;
    std::cout << "matrix destroyed\n";
}
u_it Matrix::getNumRows() {
    return n;
}
u_it Matrix::getNumCols() {
    return m;
}
int Matrix::getC(u_it i, u_it j){
    return pC[i][j];
}
void Matrix::setC(u_it i, u_it j, int v){
    pC[i][j]=v;
}
void Matrix::printMatrix(){
    for (u_it i=0; i<n; ++i){
      std::cout << "row " <<i<<" [ ";
      for(u_it j=0; j<m; ++j){
        std::cout << pC[i][j] << '\t';
      }
      std::cout << "]\n";
    }
}

主文件

#include <iostream>
#include <string>
#include <utility>
#include <algorithm>
#include <vector>

#include "matrix.h"


// sort function for my vector of pair:
bool oMyV(std::pair<uup, int> x, std::pair<uup, int> y) { return (x.second > y.second); }

// check that p is within matrix formed by a and b
bool isIn_a_b(uup p, uup a, uup b){
    bool res = false;
    if (p.first >= a.first && p.first <= b.first) {
      if (p.second >= a.second && p.second <= b.second) {
        res = true;
      }
    }
    return res;
}

int main() {
    u_it n_rows, n_cols;
    std::cout << " enter number of rows:";
    std::cin >> n_rows;
    std::cout << " enter number of cols:";
    std::cin >> n_cols;
    std::cout << " pre-computing...\n";

    std::pair<uup, int> *ps;
    std::vector<std::pair<uup, int> > myV;
    Matrix * mat=new Matrix(n_rows,n_cols);
    // print to debug:
    mat->printMatrix();
    // "PRE" computation
    for (u_it i=0; i<n_rows; ++i) {
      for (u_it j=0; j<n_cols; ++j) {
        ps=new std::pair<uup, int>(std::make_pair(i,j), mat->getC(i,j));
        myV.push_back(*ps);
      }
    }
    std::sort(myV.begin(), myV.end(), oMyV);
    /* in case you want to print ordered valuet ordered valuess for debug */
    for (std::vector<std::pair<uup, int> >::iterator it=myV.begin(); it!=myV.end(); ++it) {
      std::cout << it->second << " at [" << it->first.first <<','<<it->first.second<< "]\n";
    }
    /**/

    // call to values
    bool byebye=false;
    uup a, b;

    do {
      std::cout << " enter i,:";     std::cin >> a.first;
      std::cout << " enter j,:";     std::cin >> a.second;
      std::cout << " enter k,:";     std::cin >> b.first;
      std::cout << " enter l,:";     std::cin >> b.second;

      std::vector<std::pair<uup, int> >::iterator it=myV.begin();
      std::cout << " a:["<<a.first<<','<<a.second<<"]-b:["<<b.first<<','<<b.second<<"] in ";
      std::cout << " M:[0,0]--:["<<n_rows-1<<','<<n_cols-1<<"]\n";
      // check validity:
      if (  isIn_a_b(a, std::make_pair(0,0), std::make_pair(n_rows-1, n_cols-1) )
         && isIn_a_b(b, std::make_pair(0,0), std::make_pair(n_rows-1, n_cols-1) )
         && (a.first <= b.first)
         && (a.second <= b.second)
         ) {
        while (! isIn_a_b(it->first, a, b) && it!=myV.end()){
          ++it;
        }
        std::cout << "Found:" << it->second << " at [" << it->first.first <<','<<it->first.second<< "]\n";
      } else {
        std::cout << "makes no sense. bye.\n";
        byebye=true;
      }
    } while (!byebye);
}

生成文件

(不要忘记:在 Makefile 中制表)

OBJS = matrix.o main.o
CC = g++ -std=c++0x
DEBUG = -g
CFLAGS = -std=c++0x -Wall -c $(DEBUG)
LFLAGS = -std=c++0x -Wall $(DEBUG)
TARFILE =  ${HOME}/jcho/good/matrix.tar

p1 : $(OBJS)
        $(CC) $(LFLAGS) $(OBJS) -o p1

matrix.o: matrix.cpp matrix.h
        $(CC) $(CFLAGS) matrix.cpp

main.o: main.cpp matrix.h
        $(CC) $(CFLAGS) main.cpp

clean:
        \rm -f *.o *~ p1

tar:
        tar cfv  $(TARFILE) *.h *.cpp Makefile \
            p1 && \
            echo "tar $(TARFILE) created successfuly."
于 2016-06-29T12:34:40.763 回答