https://vjudge.net/problem/UVALive-3029
题意:
给出一个只含有F和R字母的矩阵,求出全部为F的面积最大的矩阵并且输出它的面积乘以3。
思路:
求面积最大的子矩阵,可以用扫描线。参考训练指南(orz,虽然并不知道为什么用扫描线)。
对于每一个格子包含F,我们可以把它向上拉成一条悬线,直到上面的格子为R,然后观察这条悬线可以扫到左边与右边的最大距离,那么我们所求的面积就是所有的悬线中 悬线的长度乘以(右边界 - 左边界 + 1)的最大值。
然后,需要计算悬线的长度,用up来表示,那么当这个格子为F时up(i,j) = up(i - 1,j) + 1(i >= 1),up(i,j) = 1,(i == 0);
当这个格子为R时,up(i,j) = 0。
然后,用left数组和right数组维护左右边界的信息:
我们假设lo是当前格子之前的最近的是R的格子,从左往右遍历,那么 lo 的初值是-1,那么当(i,j) 为 F时 ,left(i,j) = max(left(i-1,j),lo + 1),为什么呢,因为当前的悬线如果是包含上一行此列的格子的话,那么就要考虑上一行左边的情况了;
当(i,j)为R时,left(i,j) = 0。
维护右边界的信息同理,不同的是求最小值和从右往左遍历。
!!!:记住一边遍历,一边维护。输入也是坑!
代码:
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 6 char a[1005][1005]; 7 int up[1005][1005],right[1005][1005],left[1005][1005]; 8 9 int main() 10 { 11 int t; 12 13 scanf("%d",&t); 14 15 while(t--) 16 { 17 int m,n; 18 19 memset(a,0,sizeof(a)); 20 memset(up,0,sizeof(up)); 21 memset(right,0,sizeof(right)); 22 memset(left,0,sizeof(left)); 23 24 scanf("%d%d",&m,&n); 25 26 getchar(); 27 28 for (int i = 0;i < m;i++) 29 for (int j = 0;j < n;j++) 30 { 31 char s; 32 33 s = getchar(); 34 35 while (s != 'R' && s != 'F') s = getchar(); 36 37 if (s == 'R') a[i][j] = 0; 38 else a[i][j] = 1; 39 } 40 41 /*for (int i= 0;i < m;i++) 42 { 43 for (int j = 0;j < n;j++) printf("%d",(int)a[i][j]); 44 45 printf(" "); 46 }*/ 47 48 int ans = 0; 49 50 for (int i = 0;i < m;i++) 51 { 52 for (int j = 0;j < n;j++) 53 { 54 if (i == 0) 55 { 56 up[i][j] = a[i][j]; 57 } 58 else 59 { 60 if (a[i][j]) up[i][j] = up[i-1][j] + 1; 61 else up[i][j] = 0; 62 } 63 } 64 65 int lo = -1,ro = n; 66 67 if (i == 0) 68 { 69 for (int j = 0;j < n;j++) 70 { 71 if (a[i][j] == 0) left[i][j] = 0, lo = j; 72 else left[i][j] = lo + 1; 73 } 74 75 for (int j = n - 1;j >= 0;j--) 76 { 77 if (a[i][j] == 0) right[i][j] = n, ro = j; 78 else right[i][j] = ro - 1; 79 } 80 81 for (int j = 0;j < n;j++) 82 { 83 int tmp = up[i][j] * (right[i][j] - left[i][j] + 1); 84 85 ans = max(ans,tmp * 3); 86 } 87 } 88 else 89 { 90 for (int j = 0;j < n;j++) 91 { 92 if (a[i][j] == 0) left[i][j] = 0, lo = j; 93 else left[i][j] = max(lo + 1,left[i-1][j]); 94 } 95 96 for (int j = n - 1;j >= 0;j--) 97 { 98 if (a[i][j] == 0) right[i][j] = n, ro = j; 99 else right[i][j] = min(ro - 1,right[i-1][j]); 100 } 101 102 for (int j = 0;j < n;j++) 103 { 104 int tmp = up[i][j] * (right[i][j] - left[i][j] + 1); 105 106 ans = max(ans,tmp * 3); 107 } 108 } 109 } 110 111 /*for (int i = 0;i < m;i++) 112 { 113 for (int j = 0;j < n;j++) 114 { 115 printf("%d %d %d ",up[i][j],left[i][j],right[i][j]); 116 } 117 }*/ 118 119 printf("%d ",ans); 120 } 121 122 return 0; 123 }