Codeforces11 C. How Many Squares?(dfs,模拟)

You are given a 0-1 rectangular matrix. What is the number of squares in it? A square is a solid square frame (border) with linewidth equal to 1. A square should be at least 2 × 2. We are only interested in two types of squares:

squares with each side parallel to a side of the matrix;
squares with each side parallel to a diagonal of the matrix.

For example the following matrix contains only one square of the first type:
0000000
0111100
0100100
0100100
0111100

The following matrix contains only one square of the second type:
0000000
0010000
0101000
0010000
0000000
Regardless of type, a square must contain at least one 1 and can’t touch (by side or corner) any foreign 1. Of course, the lengths of the sides of each square should be equal.

How many squares are in the given matrix?

Input
The first line contains integer t (1 ≤ t ≤ 10000), where t is the number of test cases in the input. Then test cases follow. Each case starts with a line containing integers n and m (2 ≤ n, m ≤ 250), where n is the number of rows and m is the number of columns. The following n lines contain m characters each (0 or 1).

The total number of characters in all test cases doesn’t exceed 106 for any input file.

Output
You should output exactly t lines, with the answer to the i-th test case on the i-th line.

Examples
inputCopy
2
8 8
00010001
00101000
01000100
10000010
01000100
00101000
11010011
11000011
10 10
1111111000
1000001000
1011001000
1011001010
1000001101
1001001010
1010101000
1001001000
1000001000
1111111000
outputCopy
1
2
inputCopy
1
12 11
11111111111
10000000001
10111111101
10100000101
10101100101
10101100101
10100000101
10100000101
10111111101
10000000001
11111111111
00000000000
outputCopy
3

题意:
找到所有矩形中所有正方形,满足边都是1,且边不与其他的1接触。
边要么平行于矩形的边,要么平行于对角线。

思路:
看到边界全是1,想起了牛客那道压缩行的题目

扫描二维码关注公众号,回复: 11605850 查看本文章

假设没有边界不与其他1接触的限制条件的话,就成了一道纯大模拟(事实上我一开始就是这么写的,看错题┭┮﹏┭┮)。只要维护出每个点对应8个方向连接的连续1个数,再枚举正方形的一个点和其边长,就可以n^3的判断出所有的合法正方形了。

而有了这个限制条件以后,事实上每个点只可能存在于一个合法正方形内,所以可以直接判断。
因为要满足正方形边不与其他1解除的条件,所以合理的正方形一定满足与其组成连通块的所有1刚好组成正方形的边。

所以你可以用dfs将每个1组成的连通块染色,然后判断这些1是否刚好组成了这个正方形的边

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

typedef long long ll;

int dirx[] = { 0,1,0,-1, 1,1,-1,-1}; //右,下,左,上,左下,右下,左上,右上
int diry[] = {1, 0,-1,0,-1,1,-1,1};
int a[255][255];
int n,m;
int cnt;

void dfs(int x,int y) {
    a[x][y] = -1;
    cnt++;
    for(int d = 0;d < 8;d++) {
        int dx = x + dirx[d];
        int dy = y + diry[d];
        if(dx <= 0 || dx > n || dy <= 0 || dy > m || a[dx][dy] != 1) {
            continue;
        }
        dfs(dx,dy);
    }
}

bool judge(int i,int j,int d1,int d2,int len) {
    if(a[i][j] != -1) return false;
    for(int d = d1;d <= d2;d++) {
        int x = i,y = j;
        for(int num = 1;num <= len + 1;num++) {
            if(x <= 0 || x > n || y <= 0 || y > m || a[x][y] != -1) {
                return false;
            }
            x += dirx[d];y += diry[d];
        }
    }
    return true;
}

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n;i++) {
            for(int j = 1;j <= m;j++) {
                scanf("%1d",&a[i][j]);
            }
        }
        int ans = 0;
        for(int i = 1;i <= n;i++) {
            for(int j = 1;j <= m;j++) {
                if(a[i][j] == 1) {
                    cnt = 0;
                    dfs(i,j);
                    if(cnt == 0 || (cnt % 4 != 0) || cnt / 4 > min(n,m)) continue;
                    if(judge(i,j,0,1,cnt / 4) && judge(i + cnt / 4,j + cnt / 4,2,3,cnt / 4)) {//垂直水平的
                        ans++;
                    }
                    
                    if(judge(i,j,4,5,cnt / 4) && judge(i + cnt / 2,j,6,7,cnt / 4)) { //斜着走的
                        ans++;
                    }
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/108359710