连续相同元素最大子矩阵算法——任意多边形内近似最大矩形

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)等待大家补充……

posted @ 2020-12-24 21:30  WH01  阅读(300)  评论(0)    收藏  举报