题目链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4076
题目大意:求出给定二位矩阵中的最大的子矩阵的面积;
解析:这题实际上有点像二维DP,对与任意一个位置的[i][j]维护它的上方高度,左侧与右侧有效的可达到的位置。转移方程如下:([i][j]为空位置)height[i][j] = height[i-1][j] + 1; leftmarker[i][j] = max(left[i-1][j], leftbo + 1); rightmarker = min(rightmarker[i-1][j], rightbo - 1)。
这里leftmarker[i][j]与rightmarker[i][j]与上一行的同样列的数值是有很大关系的,不能直接用得到的左侧和右侧的最近的非空位置作为左右侧可达到的有效位置。
AC代码如下:
#include <iostream>
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <fstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <string.h>
#include <sstream>
#include <cctype>
#include <climits>
#include <set>
#include <map>
#include <deque>
#include <queue>
#include <vector>
#include <iterator>
#include <algorithm>
#include <stack>
#include <functional>
//cout << "OK" << endl;
#define _clr(x,y) memset(x,y,sizeof(x))
#define _inf(x) memset(x,0x3f,sizeof(x))
#define pb push_back
#define mp make_pair
#define FORD(i,a,b) for (int i=(a); i<=(b); i++)
#define FORP(i,a,b) for (int i=(a); i>=(b); i--)
#define REP(i,n) for (int i=0; i<(n); i++)
using namespace std;
const int INF = 0x3f3f3f3f;
const double eps = 1e-8;
const double EULER = 0.577215664901532860;
const double PI = 3.1415926535897932384626;
const double E = 2.71828182845904523536028;
typedef long long LL;
LL pow_mod(LL a,LL n,LL m)
{
if(n == 0) return 1;
LL x = pow_mod(a,n>>1,m);
LL ans = x*x%m;
if(n&1) ans = ans*a%m;
return ans;
}
int gcd(int a,int b){return b == 0 ? a : gcd(b,a%b);}
#define N 1010
int data[N][N], height[N][N], leftmarker[N][N], rightmarker[N][N];
int main(){
int t;
cin >> t;
while(t--){
int n,m;
cin >> n >> m;
getchar();
//这里尤其要注意输入的方法,应该不断读入单个字符,并在为R或F的时候进行判断
//0代表不空,1代表空
FORD(i,0,n-1){
FORD(j,0,m-1){
char ch = getchar();
while (ch != 'F'&&ch != 'R')ch = getchar();
data[i][j] = ch == 'F' ? 1 : 0;
}
}
// FORD(i,0,n-1){
// FORD(j,0,m-1){
// cout << data[i][j] << " ";
// }
// cout << endl;
// }
//这里从上而下,维护每一个点的上部最大空间,可到达的有效的左侧与右侧的位置
FORD(i,0,n-1){
int leftbo = -1;
int rightbo = m;
FORD(j,0,m-1){
if(data[i][j]){
//如果是空的,那么在第一行的时候特别处理
//其余时候,参考转移方程
if(i == 0){
height[i][j] = 1;
leftmarker[i][j] = leftbo + 1;
}
else{
height[i][j] = height[i-1][j] + 1;
leftmarker[i][j] = max(leftmarker[i-1][j], leftbo + 1);
}
}
else{
//如果当前点不空,高度显然为0,左侧可到达位置变为0列
height[i][j] = 0;
leftmarker[i][j] = 0;
leftbo = j;
}
}
//同理,处理右侧可达到位置
FORP(j,m-1,0){
if(data[i][j]){
if(i == 0) rightmarker[i][j] = rightbo - 1;
else rightmarker[i][j] = min(rightmarker[i-1][j], rightbo - 1);
}
else{
rightmarker[i][j] = m - 1;
rightbo = j;
}
}
}
int ans = 0;
FORD(i,0,n-1){
FORD(j,0,m-1){
if(data[i][j]){
ans = max(ans, height[i][j] * (rightmarker[i][j] - leftmarker[i][j] + 1));
}
}
}
cout << ans*3 << endl;
}
return 0;
}