在矩阵中寻找最大正方形连续区域

来源:互联网 发布:印度贫民窟 知乎 编辑:程序博客网 时间:2024/06/04 11:01

在矩阵中寻找最大正方形连续区域


问题描叙

输入一个矩阵M、一个数字k,找出一个最大的正方形连续区域,这个区域里的数字均是k。

p11

界的思考

对于矩阵M中的每一个元素,要么等于k要么不等于k,要知道这个数的状态,必须有一次比较。一共n个数,所以至少需要n2次比较。故比较次数的下界为Ω(n2),那么是否存在一个O(n2)的算法来解决这个问题呢?

算法

M中的每一个元素Mij都有一个与之对应的数值maxij记录着以这个元素为左上角顶点的最大的一个正方形连续区域的大小(行/列 数)。
对元素Mij有两种状态

  1. Mijk , 此时可以得出maxij=0

  2. Mij=k , 此时可以得出maxij=min(max(i+1)j,maxi(j+1),max(i+1)(j+1))+1

p10

从右到左,从下往上地扫描矩阵M,计算出每一个元素的maxij,其中最大的maxij就是矩阵M的最大正方形连续区域的大小,其对应的元素的下标(i,j)就是这块连续区域的左上角顶点。

内存使用

大可不必创建 row×column 个空间来存储每一个元素的maxij,实际上,在比较过程中只用min(row,column)+1 个内存空间就行了。

过程图示

例图:

p10

第一轮循环:
p10

第二轮循环:
p10

第三轮循环:
p10

用一个数据结构记录当前找到的最大的连续正方形的大小和对应的左上角坐标。
在比较的过程中,如果遇到更大的连续正方形,则更新记录。

代码

< header and helper >

#include<iostream>using namespace std;struct max_memo{//记录最大连续正方形区域的大小和左上角的坐标    //左上角的坐标    int row;    int col;    int num;//大小---以行or列为单位};//放回三个数中最小值。int min(int left, int down, int leftdown){    left = left < down ? left : down;    return  left < leftdown ? left : leftdown;}

< search >

void search(int M[][5],int k,int row,int col, max_memo &Max_memo){    int *memo = new int[row];     int up_one;    int current;    for (int i(0); i <row; i++){//初始化最后一行        if (M[col - 1][row - 1 - i] == k)            memo[i] = 1;        else memo[i] = 0;    }    Max_memo.col = col - 1, Max_memo.row = row - 1, Max_memo.num = memo[0];//初始化    int ex_index;//记录交换时的下标。    for (int row_local(row - 2), col_local(col - 1); row_local >= 0;)//外循环。    {        col_local = (col - 1);//初始化列坐标---每次内循环从最右边开始,向左移动。        if (M[row_local][col_local] == k) {            up_one = 1;//计算最右端的元素的最大连续区域(0 or 1)            if (up_one > Max_memo.num){                Max_memo.col = col_local, Max_memo.row = row_local, Max_memo.num = up_one;//更新            }        }        else up_one = 0;        col_local--;        while (col_local >= 0){//内循环            ex_index = (col - 1) - col_local-1;            if (M[row_local][col_local] != k){                  current = 0;                            }            if (M[row_local][col_local] == k){                current = min(up_one, memo[ex_index + 1], memo[ex_index]) + 1;                if (current > Max_memo.num){                    Max_memo.col = col_local, Max_memo.row = row_local, Max_memo.num = current;//更新                }            }            memo[ex_index] = up_one;            up_one = current;            col_local--;//向左移               }        memo[row - 1] = up_one;//第一轮循环结束。        row_local--;//向上移    }    delete[] memo;}

< main >

int main(){    int M[][5] = {    /*  { 0, 1, 1, 1, 1 },        { 0, 1, 2, 2, 1 },        { 1, 1, 2, 2, 1 },        { 1, 1, 2, 2, 1 },        { 1, 1, 0, 0, 1 }    */        {0,0,0,0,1},        {0,0,0,0,1},        {0,0,0,0,1},        {0,0,0,0,1},        {0,0,0,0,0}    };    max_memo Max_memo;    int k = 1;    search(M, k, 5, 5, Max_memo);    if (Max_memo.num)    cout << "结果: 坐标(" << Max_memo.row << ", " << Max_memo.col << "); 大小(以行为单位): " << Max_memo.num << endl;    else cout << "没有值为"<<k<<"的连续正方形区域" << endl;    cout << endl;    system("pause");}
0 0
原创粉丝点击