題目鏈接:
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;
}