Number of submatricies containing all zeros

对着背影说爱祢 提交于 2021-02-07 09:27:50

问题


Is there a way to find a number of rectangular submatrices containing all zeros with a complexity smaller than O(n^3), where n is the dimension of given matrix?


回答1:


Here is a solution O(n² log n).

First, let's convert the main problem to something like this:

For given histogram, find the number of submatrices containing all zeros.


How to convert it ?

For each position calculate the height of column that start on that position and contain only zeros.

Example:

10010    01101
00111    12000
00001 -> 23110
01101    30020
01110    40001

It can be easily find in O(n²).

for(int i = 1; i <= n; i++)
    for(int j = 1; j <= m; j++)
        up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j];

Now we can consider each row as histogram with given heights.


Let's solve the problem with histogram.

Our goal is to travel all heights from left to right, and on each step we are going to update array L. This array for each height is going to contain maximum widths so that we can make a rectangle of this width from current position, to the left and of given height.

Consider example:

0
0   0
0 000
00000   -> heights: 6 3 4 4 5 2
000000
000000

L[6]:   1     0     0     0     0     0
L[5]:   1     0     0     0     1     0
L[4]:   1     0     1     2     3     0
L[3]:   1     2     3     4     5     0
L[2]:   1     2     3     4     5     6
L[1]:   1     2     3     4     5     6
steps:  1     2     3     4     5     6

As you can see if we add all those numbers we will receive an answer for given histogram.

We can simply update array L in O(n), however we can also do it in O(log n) by using segment tree (with lazy propagation) that can add in interval, set value in interval and get sum from interval.

In each step we just add 1 to interval [1, height] and set 0 in interval[height + 1, maxHeight] and get sum from interval [1, maxHeight].

height - height of current column in histogram.

maxHeight - maximum height of column in histogram.

And thats how you can get O(n² * log n) solution :)


Here is main code in C++:

const int MAXN = 1000;
int n;
int arr[MAXN + 5][MAXN + 5]; // stores given matrix
int up[MAXN + 5][MAXN + 5]; // heights of columns of zeros
long long answer;

long long calculate(int *h, int maxh) { // solve it for histogram
    clearTree();

    long long result = 0;
    for(int i = 1; i <= n; i++) {
        add(1, h[i]); // add 1 to [1, h[i]]
        set(h[i] + 1, maxh); // set 0 in [h[i] + 1, maxh];
        result += query(); // get sum from [1, maxh]
    }

    return result;
}
int main() {
    ios_base::sync_with_stdio(0);
    cin >> n;

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            cin >> arr[i][j]; // read the data

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= n; j++)
            up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j]; // calculate values of up

    for(int i = 1; i <= n; i++)
        answer += calculate(up[i], i); // calculate for each row

    cout << answer << endl;
}

Here is the beginning of code, segment tree:

#include <iostream>
using namespace std;

// interval-interval tree that stores sums

const int p = 11;
int sums[1 << p];
int lazy[1 << p];
int need[1 << p];
const int M = 1 << (p - 1);

void update(int node) {
    if(need[node] == 1) { // add
        sums[node] += lazy[node];
        if(node < M) {
            need[node * 2] = need[node * 2] == 2 ? 2 : 1;
            need[node * 2 + 1] = need[node * 2 + 1] == 2 ? 2 : 1;
            lazy[node * 2] += lazy[node] / 2;
            lazy[node * 2 + 1] += lazy[node] / 2;
        }
    } else if(need[node] == 2) { // set
        sums[node] = lazy[node];
        if(node < M) {
            need[node * 2] = need[node * 2 + 1] = 2;
            lazy[node * 2] = lazy[node] / 2;
            lazy[node * 2 + 1] = lazy[node] / 2;
        }
    }
    need[node] = 0;
    lazy[node] = 0;
}

void insert(int node, int l, int r, int lq, int rq, int value, int id) {
    update(node);
    if(lq <= l && r <= rq) {
        need[node] = id;
        lazy[node] = value * (r - l + 1);
        update(node);
        return;
    }
    int mid = (l + r) / 2;
    if(lq <= mid) insert(node * 2, l, mid, lq, rq, value, id);
    if(mid + 1 <= rq) insert(node * 2 + 1, mid + 1, r, lq, rq, value, id);
    sums[node] = sums[node * 2] + sums[node * 2 + 1];
}


int query() {
    return sums[1]; // we only need to know sum of the whole interval
}

void clearTree() {
    for(int i = 1; i < 1 << p; i++)
        sums[i] = lazy[i] = need[i] = 0;
}

void add(int left, int right) {
    insert(1, 0, M - 1, left, right, 1, 1);
}

void set(int left, int right) {
    insert(1, 0, M - 1, left, right, 0, 2);
}

// end of the tree


来源:https://stackoverflow.com/questions/23089080/number-of-submatricies-containing-all-zeros

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!