您的位置:首页 > 其它

《算法竞赛-训练指南》第一章-1.22_LA 3209

2013-07-22 21:56 232 查看
这道题目也蛮好的,是求满足条件最大子矩阵的,用到的方法非常的独特。

这道题目容易想到的是暴力,枚举每个点,以每个点作为起点在枚举边长,这样的操作肯定超时,而题解中给的方法就非常的棒了,把每个点的周围状态压缩一下,压缩成一个带上下左右的结点来表达周围的状况,例如up[i][j] 代表的就是以这个点的周围的矩形最大高度,left[i][j]表示这个矩形能到的最左边的左边, right[i][j]表示这个矩形能到的最右边的距离。知道了这些信息,其实扫一遍所有的点不就能出来最大的面积了么?

当然重要的就是更新每个结点的问题,这个题目也是很好的,当这个点是不能被利用的,那么这个点的up = 0,左断点为0,又断电为N - 1,为什么要这么设计呢?因为下面的更新非常重要(例如,假设第一排全部都不能用,而第二排中有能用的,你的那个递推公式要能用的话,left[i][j] = max(left[i - 1][j], lo + 1) , right[i][j] = min(right[i][j], lo - 1)假设第二排第三个点到最后一个点都能用,你要保证能更新成功所有的right[i][j]的话,那么必须使得不能用时的右端点为N
- 1,请自行举例验证一下,当然left是一样的道理的)。


难点就是模型的建立和left和right的具体递推和注意事项。

贴出代码:

#include <stdio.h>
#include <string.h>
#include <string>

using namespace std;

const int MAXN = 1000 + 11;

int N, M;

int map[MAXN][MAXN];

int up[MAXN][MAXN];

int left[MAXN][MAXN];

int right[MAXN][MAXN];

int main()
{
char str[10];
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &N, &M);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
scanf("%s", str);
map[i][j] = (str[0] == 'R') ? 0 : 1;
}
}
int lo = -1;
for (int j = 0; j < M; j++)
{
if (map[0][j] == 0)
{
up[0][j] = left[0][j] = 0;
lo = j;
}
else
{
up[0][j] = 1;
left[0][j] = lo + 1;
}
}
lo = M;
for (int j = M - 1; j >= 0; j--)
{
if (map[0][j] == 0)
{
right[0][j] = N - 1;
lo = j;
}
else
{
right[0][j] = lo - 1;
}
}
int ans = 0;
for (int i = 1; i < N; i++)
{
lo = -1;
for (int j = 0; j < M; j++)
{
if (map[i][j] == 0)
{
up[i][j] = 0;
left[i][j] = 0;
lo = j;
}
else
{
up[i][j] = up[i - 1][j] + 1;
left[i][j] = max(left[i - 1][j], lo + 1);
}
}
lo = M;
for (int j = M - 1; j >= 0; j--)
{
if (map[i][j] == 0)
{
up[i][j] = 0;
right[i][j] = M - 1;
lo = j;
}
else
{
right[i][j] = min(right[i - 1][j], lo - 1);
}
int t = (right[i][j] - left[i][j] + 1) * up[i][j];
if (ans < t)
{
ans = t;
}
}
}
printf("%d\n", ans * 3);
}
// system("pause");
return 0;
}
/*
5 5
R R R R R
R R R R R
R R R F F
R R R R R
R R R R R
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: