输入一个n*m的矩阵,每个格子可能是空地,也可能是沼泽。对于每个空地格子,求出以它为右下角的空矩形的最大周长,然后统计每个周长出现了多少次。
输入包含多组测试数据,第一行输入一个正整数N,表示输入样例组数(N<=10)
每组测试样例第一行为正整数n和m(1<=n,m<=1000)
以下n行,每行包含m个字符,用'#'表示沼泽,'.'表示土地
输出数据包含多行,用"a x b"来表示周长为b的矩形出现了a次,按照矩形周长从小到大排序
1
6 5
..#.#
.#...
#..##
...#.
#....
#..#.
6 x 4
5 x 6
5 x 8
3 x 10
1 x 12
显而易见,我们要维护一个单调上升的关于每列高度的栈,然而此题仅仅维护高度明显不够,对于一个矩形的边长,我们可有宽度和高度得知。
对于单调栈的每一个元素,我们维护宽度和高度两个元素,为此列的高度和最左端的位置。对于一个矩形,我们有周长=(h+j-c+1)*2,由于对于每一列,j一定,所以h+c最大就是周长最大,因此我们的单调栈不仅要维护长度递增,还要在插入时有所选择,维护h+c的单调递增序列。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 struct data 9 { 10 int x,y; 11 }sta[1001]; 12 int n,m; 13 char a[1001][1001]; 14 int h[1001]; 15 int ans[5001]; 16 int main() 17 { 18 int t; 19 scanf("%d",&t); 20 while(t--) 21 { 22 memset(ans,0,sizeof(ans)); 23 memset(h,0,sizeof(h)); 24 scanf("%d%d",&n,&m); 25 for(int i=1;i<=n;i++)scanf("%s",a[i]+1); 26 for(int i=1;i<=n;i++) 27 { 28 int head=0; 29 for(int j=1;j<=m;j++) 30 { 31 int he=h[j],k=j; 32 if(a[i][j]=='#'){h[j]=0;head=0;} 33 else 34 { 35 he++;h[j]++; 36 while(head>=1&&sta[head].x>=h[j]){k=sta[head].y;head--;} 37 if(!head||he-k>sta[head].x-sta[head].y){sta[++head]=(data){he,k};} 38 ans[sta[head].x+j-sta[head].y+1]++; 39 } 40 } 41 } 42 for(int i=2;i<=m+n;i++) if(ans[i]) printf("%d x %d ",ans[i],i*2); 43 } 44 }