连续相同元素最大子矩阵算法——任意多边形内近似最大矩形
1.测试用例
本次以0-1组成的二维矩阵matrix[rows,cols]为例:
0010100
0111110
1110111
0111110
0010100
2.遍历行rows、列cols的得到dp[cols+1]:
00101000
01212100
12303210
03414300
00505000
dp[cols+1]为累计每列连续为1的个数,遇1加1,遇0置0
3.获取最大子矩阵算法过程
遍历第1行:
判断dp[j] < dp[j - 1],直到dp[3]<dp[2]为true,开始计算这个位置往前的最大子矩阵。
此处反方向遍历,计算出w(宽度为反向遍历的次数)和h(高为反向遍历dp[k]中最小的值,目的是保证等高),得到临时面积tempMax=w*h,与之前的最大面积max比较留最大,得到最大面积1,max[4]:{0,2,0,2}。
直到dp[k] < 1终止反向循环,接着循环j。
dp[4]跟dp[2]一样过程,面积1,max[4]:{0,4,0,4}。
遍历第2~n行:
同样的思路。
第1、2行最大值子矩阵:

第3行最大值子矩阵:

第4行最大值子矩阵:

第5行最大值子矩阵:

4.获取最大子矩阵算法
以下代码在上面的思路是添加了条件:
(1)过滤掉单行或者单列的情况,即过滤掉高或者宽等于1的情况;
(2)如最大面积相等,选择靠近矩阵中心的子矩阵。
/// <summary>
/// 获取0-1阵矩中连续相同元素最大子矩阵
/// </summary>
/// <param name="matrix"></param>
/// <returns name="res">int[]:最大矩阵对应下标</returns>
public int[] GetMaxMatrix(int[,] matrix)
{
int rows = matrix.GetLength(0); // 返回的是第一维的长度,行数
int cols = matrix.GetLength(1); // 返回的是第二维的长度,列数
int max = 0;//存放最大矩阵面积值
int[] res = new int[4];//存放最大矩阵左下角和右上角下标
int[] dp = new int[cols + 1];//存放行元素累计为1个数
//循环行
for (int i = 0; i < rows; i++)
{//循环列,多循环一次是作为最右侧连续为1个数计算终止条件,原理是先按行算连续为1的个数,直到个数小于之前的为止反向开始算最大面积
for (int j = 0; j < cols + 1; j++)
{//j < cols防止matrix[i,j]溢出;遇1累加,记录高度;遇0重置0
dp[j] = j < cols && matrix[i, j] == 1 ? dp[j] + 1 : 0;//可修改matrix[i, j] == 1来判断别的数字矩阵
if (j > 1 && dp[j] < dp[j - 1] && dp[j - 1] > 1 && dp[j - 2] > 1)//过滤长或宽等于1的情况,可根据需求更改判断条件
{
int h = dp[j - 1];//高
int w = 2;//宽由2开始累加,过滤长或宽等于1的情况,可根据需求更改判断条件
//遍历计算最大值
for (int k = j - 2; k >= 0; k--)
{
if (dp[k] < 2 || h < 2) //遍历遇dp=0或者高度h小于2终止,过滤长或宽等于1的情况,可根据需求更改判断条件
break;
else
h = dp[k] < h ? dp[k] : h;
int tempMax = w * h; //此次面积
int[] tempRes = new int[] { i - h + 1, j - w, i, j - 1 };//此次左下角右上角下标
w++;//宽度累加
//保留面积最大者,后期可根据具体需求调整
if (max < tempMax)
{
max = tempMax;//最大矩阵值
res = tempRes;//最大矩阵对应下标
}
else if (max == tempMax)//当面积一样时,选择矩形居中的情况,,可根据需求更改判断条件
{
double[] tempCentre = new double[] { (tempRes[2] + tempRes[0]) / 2.0, (tempRes[3] + tempRes[1]) / 2.0 };//临时矩形中心
double[] maxCentre = new double[] { (res[2] + res[0]) / 2.0, (res[3] + res[1]) / 2.0 };//上次最大矩形中心
double d1 = GetDistance((rows - 1) / 2.0, (cols - 1) / 2.0, tempCentre[0], tempCentre[1]);
double d2 = GetDistance((rows - 1) / 2.0, (cols - 1) / 2.0, maxCentre[0], maxCentre[1]);
if (d1 < d2)
{
max = tempMax;//最大矩阵值
res = tempRes;//最大矩阵对应下标
}
}
}
}
}
}
return res;//返回最大矩阵对应下标
}
/// <summary>
/// 计算两点距离
/// </summary>
/// <param name="aX"></param>
/// <param name="aY"></param>
/// <param name="bX"></param>
/// <param name="bY"></param>
/// <returns></returns>
private static double GetDistance(double aX, double aY, double bX, double bY)
{
double x = System.Math.Abs(bX - aX);
double y = System.Math.Abs(bY - aY);
return Math.Sqrt(x * x + y * y);
}
4.适用场景
(1)求任意多边形、不规则弧面内近似最大矩形:构造点阵列格网,判断点面关系生成0-1矩阵,使用上述算法即可求得。
(2)等待大家补充……

浙公网安备 33010602011771号