hdu 2483
地址:http://acm.hdu.edu.cn/showproblem.php?pid=2483
题意:给一个n*m的0-1矩阵。在里面找符合条件的方阵。条件有3个:1.方阵的4条边上全为1;2.方阵内(除了4条边的)0和1的个数之差不超过1;3.方阵大小至少为2*2。问能找到几个这样的方针。
mark:最朴素的做法是枚举所有的1当做要找的方阵左上角的元素。然后判断四边是否全为1,再统计内部0和1的个数。但是每次判断边上的1和计算内部1的数量复杂度太高,肯定是不行的。
我们用一个数组sum[i][j]表示从矩形左上角到(i,j)这个位置里1的个数。在计算区域内1的个数的时候可以利用这个sum[i][j]数组得到。sum[i][j]需要预处理出来:sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+g[i][j]。
我们用一个数组row[i][j]表示第i行中第j个元素是“连续的第几个1”。例如111011对应的row[i]就是123012。判断横边是否是连续的1的时候,可以用row[i][right]-row[i][left-1]的结果和right-left比较,相同则全为1。row数组需要预处理出来:row[i][j] = (g[i][j]?row[i][j-1]+1:0);
竖边也是这样预处理出来。
这样判断一个给定的方阵是否符合要求,只需要利用上面3个辅助数组,O(1)地完成,复杂可以符合要求了。
代码:
1 # include <stdio.h> 2 # include <string.h> 3 4 5 int g[310][310] ; 6 int sum[310][310] ; 7 int row[310][310], col[310][310] ; 8 int n, m ; 9 10 11 int abs(int x){return x<0?-x:x;} 12 13 14 int check(int x, int y, int xx, int yy) 15 { 16 int _1 = sum[xx-1][yy-1]-sum[xx-1][y]-sum[x][yy-1]+sum[x][y] ; 17 int _0 = (xx-x-1)*(yy-y-1) - _1 ; 18 if (abs( _1 - _0) > 1) return 0 ; 19 if (row[x][yy] - row[x][y] != yy-y) return 0 ; 20 if (row[xx][yy]-row[xx][y] != yy-y) return 0 ; 21 if (col[xx][y] - col[x][y] != xx-x) return 0 ; 22 if (col[xx][yy] - col[x][yy] != xx-x) return 0 ; 23 return 1 ; 24 } 25 26 27 int main () 28 { 29 int T ; 30 int i, j, k ; 31 int l, t, r, d, ans ; 32 int flag ; 33 34 scanf ("%d", &T) ; 35 while (T--) 36 { 37 scanf ("%d%d", &n, &m) ; 38 for (i = 1 ; i <= n ; i++) 39 for (j = 1 ; j <= m ; j++) 40 scanf ("%d", &g[i][j]), 41 sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+g[i][j], 42 row[i][j] = ((g[i][j])?(row[i][j-1]+1):0), 43 col[i][j] = ((g[i][j])?(col[i-1][j]+1):0) ; 44 ans = 0 ; 45 for (i = 1 ; i <= n ; i++) 46 for (j = 1 ; j <= m ; j++) if (g[i][j]) 47 for (k = 1 ; i+k<=n && j+k<=m ; k++) 48 if (check(i,j,i+k,j+k)) ans++ ; 49 printf ("%d\n", ans) ; 50 } 51 return 0 ; 52 }