您的位置:首页 > 其它

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

2016-04-17 16:28 477 查看

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

问题描叙

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





界的思考

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

算法

M中的每一个元素MijM_{ij}都有一个与之对应的数值maxijmax_{ij}记录着以这个元素为左上角顶点的最大的一个正方形连续区域的大小(行/列 数)。

对元素MijM_{ij}有两种状态

Mij≠kM_{ij}\ne k , 此时可以得出maxij=0max_{ij}=0。

Mij=kM_{ij} = k , 此时可以得出maxij=min(max(i+1)j,maxi(j+1),max(i+1)(j+1))max_{ij}=min(max_{(i+1)j},max_{i(j+1)},max_{(i+1)(j+1)})。





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

内存使用

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

过程图示

例图:





第一轮循环:




第二轮循环:




第三轮循环:




用一个数据结构记录当前找到的最大的连续正方形的大小和对应的左上角坐标。

在比较的过程中,如果遇到更大的连续正方形,则更新记录。

代码

< 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");

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: