題目:https://www.luogu.org/problemnew/show/P1169ios
題意:n*m的黑白格子,找到面積最大的黑白相間的正方形和矩形。spa
思路:傳說中的懸線法!用下面這張圖說明一下。code
懸線法通常是用來求一個沒有障礙點的最大子矩陣的。想象從上面垂下來好多的懸線,這些懸線被一個底所限制,而且能夠左右移動可是也有範圍限制。blog
如今某條懸線能夠移動到的面積就是他能知足的子矩形的面積。好比咱們已經處理好了$i-1$行,如今考慮$(i,j)$get
對於這道題來講,若是$grid[i][j]!=grid[i-1][j]$就說明他們黑白顏色不一樣,那麼這個以$i$行爲底的懸線的高度就是$height[i-1][j]+1$string
接下來咱們考慮他的左右範圍it
首先咱們能夠須要預處理出每一個位置能夠到的左右範圍,好比說$lft[i][j]$就是從$(i,j)$開始往左知足左右相間能夠一直到第幾列。io
當咱們要擴展一行的時候對於左邊界只能取最右邊的一個,對於右邊界只能取最左邊的。class
1 #include<cstdio> 2 #include<cstdlib> 3 #include<map> 4 #include<set> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #include<stack> 10 #include<queue> 11 #include<iostream> 12 13 #define inf 0x3f3f3f3f 14 using namespace std; 15 typedef long long LL; 16 typedef pair<int, int> pr; 17 18 int n, m; 19 const int maxn = 2005; 20 int grid[maxn][maxn]; 21 int lft[maxn][maxn], rgt[maxn][maxn], height[maxn][maxn]; 22 23 int main() 24 { 25 scanf("%d%d", &n, &m); 26 for(int i = 1; i <= n; i++){ 27 for(int j = 1; j <= m; j++){ 28 scanf("%d", &grid[i][j]); 29 lft[i][j] = rgt[i][j] = j; 30 height[i][j] = 1; 31 } 32 } 33 34 for(int i = 1; i <= n; i++){ 35 for(int j = 2; j <= m; j++){ 36 if(grid[i][j] != grid[i][j - 1]){ 37 lft[i][j] = lft[i][j - 1]; 38 } 39 } 40 for(int j = m - 1; j > 0; j--){ 41 if(grid[i][j] != grid[i][j + 1]){ 42 rgt[i][j] = rgt[i][j + 1]; 43 } 44 } 45 } 46 47 int anssqu = 0, ansrec = 0; 48 for(int i = 1; i <= n; i++){ 49 for(int j = 1; j <= m; j++){ 50 if(i > 1 && grid[i][j] != grid[i - 1][j]){ 51 lft[i][j] = max(lft[i][j], lft[i - 1][j]); 52 rgt[i][j] = min(rgt[i][j], rgt[i - 1][j]); 53 height[i][j] = height[i - 1][j] + 1; 54 } 55 int row = rgt[i][j] - lft[i][j] + 1; 56 int col = min(row, height[i][j]); 57 anssqu = max(anssqu, col * col); 58 ansrec = max(ansrec, row * height[i][j]); 59 } 60 } 61 62 printf("%d\n%d\n", anssqu, ansrec); 63 }