我的代码遍历了一个免费网格"阻止"位置;并找到最大的矩形。
这很好用。但是,我需要能够找到具有更具体标准的矩形。请考虑以下事项:
00X0000000
000000####
##########
####000000
0000000000
0000000000
在此图中; 0标记可用位置,#标记占用位置,X标记所需点。
我现在的代码将找到网格的右下区域,因为它确实是最大的矩形。但是,我想要的答案包含X位置(左上角的矩形)。
我不知道如何添加这个额外的标准。我试着跟踪坐标;抛弃不含X的结果;但这并不是一直有效。在某些情况下,我会得到比想要的小的矩形(可能是因为我穿过网格的顺序)
我发现的所有算法似乎只能找到最大的矩形和矩形的坐标。我无法找到任何能够可靠地排除不包含特定点的结果。
有人能指出我正确的方向,和/或提供实施吗?
修改: 由于评论不能有换行符,我需要使用此区域来解释shole实现的问题。它不适用于以下情况:
#0#X
###0
#000
####
0#00
0000
0000
在上面的示例中,返回的坐标形成如下:
0#X
##0
000
答案应该是1x3,而不是3x3
另一个失败的例子:
0#X#
0000
00##
000#
0000
返回:
#X
00
在这种情况下,返回的答案应该是1x2区域,而不是它认为是2x2。
在某些情况下,它返回的区域大于整个网格的区域,坐标超出有效坐标范围。
这适用于SOMETIMES,但它通常不正确而且不正确。它总是返回包含该点的区域;只是错误的区域/坐标。
答案 0 :(得分:1)
有趣的问题,这是我的O(R * C)算法,R =#rows,C = #columns
这个想法很简单,蛮力将每个点作为潜在的矩形的底部边界,然后尝试尽可能高地爬上以获得最大高度,然后获得该垂直线的最大左右距离
这会测试所有潜在的矩形,但我们必须快速完成。 我们通过逐行动态编程为每个(i,j)计算最大高度,最大左右距离。
然后我们可以测试X是否在这个潜在的矩形内,如果是的话,我将无限大偏移添加到这个矩形的区域,它足够大,任何矩形都不包含X将小于它,而其他矩形,如果包含X并且大于它,我们仍然可以选择那个矩形。
在算法结束后,我们得到最大 Area + Offset ,我们从中减去偏移并将区域恢复。
如果您运行代码(C ++)并查看下面的日志,并通过以下输入更容易理解:
6 10
00X0000000
000000####
##########
####000000
0000000000
0000000000
#include<bits/stdc++.h>
using namespace std;
char w[20][20];
int tl[20][20] = {0}, tr[20][20] = {0}, h[20][20] = {0}, l[20][20]={0}, r[20][20]={0};
int ans, R,C, xr,xc, ar1, ac1, ar2, ac2;
int largestRect()
{
int area = 0;
for(int i=0; i<20;i++) for(int j=0; j<20;j++) l[i][j] = r[i][j] = 1<<28;
for(int i=1; i<=R;i++){
for(int j=1; j<=C;j++)
if(w[i][j]!='#') tl[i][j] = tl[i][j-1]+1;
else tl[i][j] = 0;
for(int j=C; j>=1; j--)
if(w[i][j]!='#') tr[i][j] = tr[i][j+1]+1;
else tr[i][j] = 0;
for(int j=1; j<=C; j++)
if(w[i][j]!='#') h[i][j] = h[i-1][j]+1;
else h[i][j] = 0;
for(int j=1; j<=C; j++)
if(w[i][j] != '#') l[i][j] = min(tl[i][j], l[i-1][j]);
for(int j=1; j<=C; j++)
if(w[i][j] != '#') r[i][j] = min(tr[i][j], r[i-1][j]);
for(int j=1; j<=C;j++){
int offset = 0;
if((r[i][j]+l[i][j]-1)*h[i][j] > 0){
if(xr >= i-h[i][j]+1 && xr <= i && xc >= j-l[i][j]+1 && xc <= j+r[i][j]-1) offset = 1<<28;
printf("Top left = (%d,%d) Bottom right = (%d,%d)\n", i-h[i][j]+1, j-l[i][j]+1,i, j+r[i][j]-1);
printf("Area = %d\n", (r[i][j]+l[i][j]-1)*h[i][j]);
printf("Included X? %d\n", xr >= i-h[i][j]+1 && xr <= i && xc >= j-l[i][j]+1 && xc <= j+r[i][j]-1 );
printf("Area with offset = %d\n\n", (r[i][j]+l[i][j]-1)*h[i][j] + offset);
if(area <= (r[i][j]+l[i][j]-1)*h[i][j] + offset){
area = max(area, (r[i][j]+l[i][j]-1)*h[i][j] + offset);
ar1 = i-h[i][j]+1; ac1 = j-l[i][j]+1; ar2 = i; ac2 = j+r[i][j]-1;
}
}
}
}
return area;
}
int main(){
scanf("%d %d", &R, &C);
for(int i=0; i<20;i++) for(int j=0; j<20;j++) w[i][j] = '#';
for(int i=1; i<=R; i++){
getchar();
for(int j=1; j<=C; j++){
w[i][j] = getchar();
if(w[i][j] == 'X'){ xr = i; xc = j;}
}
}
ans = largestRect() - (1<<28);
printf("Largest Rect Containing X is (%d,%d) to (%d,%d), with area = %d\n", ar1, ac1, ar2, ac2, ans);
return 0;
}
编辑部分:详细解释的算法/代码
首先,这是我们的O(R * C)算法的概要:
然后我们将看到如何在算法中执行步骤2-3,我们将使用动态编程。
让我们定义几个数组:
h[i][j] := the highest height you can reach starting at (i,j)
tr[i][j] := the longest distance to right you can reach starting at (i,j)
tl[i][j] := the longest distance to left you can reach starting at (i,j)
应该能够看到这三个阵列可以使用O(R * C)预先计算
h[i][j] = h[i-1][j]+1 if(i,j) is empty, else h[i][j] = 0
similarly
tr[i][j] = tr[i][j+1]+1 if(i,j) is empty, else tr[i][j] = 0
tl[i][j] = tl[i][j-1]+1 if(i,j) is empty, else tl[i][j] = 0
现在我们再定义两个数组
l[i][j] := the longest distance to right you can reach starting from
line (i,j) and (i-h[i][j]+1,j) (That's simply just put h[i][j] into consideration)
与r [i] [j]类似,请确保您理解tl [i] [j]和l [i] [j](tr [i] [j]和r [i]之间的区别[ j])
现在l [i] [j]和r [i] [j]也可以使用O(R * C)预先计算!
一点不同是他们需要h [i] [j]和tr [i] [j](或tl [i] [j])来计算它,
所以h [i] [j],tl [i] [j],tr [i] [j]必须在l [i] [j]和r [i] [j]之前计算。
l[i][j] = min(l[i-1][j], tl[i][j]) if(i,j) is empty, else l[i][j] = tl[i][j]
r[i][j] = min(r[i-1][j], tr[i][j]) if(i,j) is empty, else r[i][j] = tr[i][j]
您可以认为它说的是以下陈述:
l [i] [j]是最小tl [X] [j] ,在[i-h [i] [j] +1,i]中的X
所以l [i] [j]是(i,j)到最大高度的最大距离
与r [i] [j]
类似所以我的代码正在使用两个for循环来完成上面描述的动态编程,它似乎很复杂,因为我在使用之前没有预先计算它们
我计算这些数组并使用它们来计算矩形区域即时。话虽如此,你总是可以先预先计算所有这些数组,然后再计算最大面积,时间复杂度仍为O(R * C)