题目
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1030
题意
矩阵,有障碍和普通地面两种子元素,求普通地面连成的子矩阵面积最大值 * 3
思路
如刘书
对于子矩阵长方形来说,其底边上必然有一点,该点向上可以延伸的距离就是子矩阵的长,枚举这一点,设为(i,j)。(i,j)不是障碍是普通地面。
令up[i][j]为其向上能延伸的距离,llen[i][j]为以up[i][j]为长的长方形,左边最早开始于哪里,rlen[i][j]为依此右边最晚结束于哪里。
up[i][j]=(i?up[i - 1][j] + 1)
但要如何更新llen和rlen呢?
考虑上方(i - 1, j),如果(i - 1, j)是障碍,那么up[i][j] = 1, llen[i][j]就是(i, j)左边的障碍横坐标+1,rlen以此类推。
如果(i- 1, j)不是障碍,第一种情况,llen[i][j] = llen[i - 1][j],在这多填出的一层内没有障碍物,另一种情况,llen[i][j]依然是(i, j)左边的障碍横坐标+1。
rlen以此类推。
感想
1. 一开始没有想到枚举(i,j)这根作为面积的长,而只是想到枚举(i,j)作为右下角。这样就还要用费时间的方式确定此时的面积长。
2. 后来没想到可以用上方而不是左方来更新rlen或者llen。没有意识到如果上方是障碍,那么只要看左/右的障碍在哪里即可。
3. 最后本来用的是(i && maze[i - 1][j] != 'R'),不知道哪里错了
代码
#include <algorithm> #include <cassert> #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <queue> #include <set> #include <tuple> #define LOCAL_DEBUG using namespace std; const int MAXN = 1e3 + 4; char maze[MAXN][MAXN]; int up[MAXN][MAXN]; int llen[MAXN][MAXN]; int rlen[MAXN][MAXN]; int main() { #ifdef LOCAL_DEBUG freopen("C:\Users\Iris\source\repos\ACM\ACM\input.txt", "r", stdin); //freopen("C:\Users\Iris\source\repos\ACM\ACM\output.txt", "w", stdout); #endif // LOCAL_DEBUG int T; scanf("%d", &T); for (int ti = 1; ti <= T; ti++) { int n, m; scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { char tmp[2]; scanf("%s", tmp); maze[i][j] = tmp[0]; } } for (int i = 0; i < n; i++) { for (int j = 0, last_impede=-1; j < m; j++) { if (maze[i][j] == 'R') { up[i][j] = 0; llen[i][j] = 0; last_impede = j; } else { up[i][j] = (i ? up[i - 1][j] : 0) + 1; llen[i][j] = max((i ? llen[i - 1][j] : 0), last_impede + 1); } } } int ans = 0; for (int i = 0; i < n; i++) { for (int j = m - 1, last_impede = m; j >= 0; j--) { if (maze[i][j] == 'R') { rlen[i][j] = m; last_impede = j; } else { rlen[i][j] = min((i ? rlen[i - 1][j] : m), last_impede - 1); ans = max(ans, up[i][j] * (rlen[i][j] - llen[i][j] + 1)); } } } printf("%d ", ans * 3); } return 0; }