hdu - 4331 - Image Recognition - 扫描线

本文提供了一种算法解决在01图中找到以1为边的正方形的数量问题,包括初始化数据结构、构建算法、实现更新和查询操作,并通过实例演示了求解过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求在01图中,以1为边的正方形有几个。http://acm.hdu.edu.cn/showproblem.php?pid=4331

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#define lson l, m , rt << 1
#define rson m + 1, r , rt << 1 | 1
#define maxn 1010
int T, n, grid[maxn][maxn], d[maxn][maxn], u[maxn][maxn];
int r[maxn][maxn], c[maxn][maxn], sum[maxn << 2];
using namespace std;
void build(){
    memset(sum, 0, sizeof(sum));
}
void update(int pos, int l, int r, int rt){
    ++ sum[rt];
    if(l == r) return ;
    int m = (l + r) >> 1;
    if(pos <= m) update(pos, lson);
    else update(pos, rson);
}
int query(int pos, int l , int r, int rt){
    if(l == r) return sum[rt];
    int m = (l + r) >> 1;
    int ret = 0;
    if(pos <= m) ret += query(pos, lson) + sum[rt << 1 | 1];
    else if(pos > m) ret += query(pos, rson);
    return ret;
}
struct Data{
    int p, x;
}g[maxn * 2];
bool cmp(Data a, Data b){
    return a.p < b.p ||(a.p == b.p && a.x < b.x);
}

for(int i = n; i > 1; -- i){
    ans += solve(i, 1, n - i + 1);
}
for(int i = 1; i <= n; i ++){
    ans += solve(1, i, n - i + 1);
}
int solve(int xx, int yy, int n){
    int e = 0, m = 0, ret = 0;
    for(int k = 1, i = xx, j = yy; k <= n; k ++, i ++, j ++){
        if(grid[i][j]){
            g[m].p = k - u[i][j], g[m ++].x = -k;
            g[m].p = k, g[m ++].x = k;
        }
    }
    sort(g, g + m, cmp);
    build(); 
    for(int k = 1, i = xx, j = yy; k <= n; k ++, i ++, j ++){
        if(grid[i][j]){
            update(k + d[i][j] - 1, 1, n, 1);
        }
        while(e < m && g[e].p <= k){
            if(g[e].p == k){
                if(g[e].x < 0)
                    ret -= query(-g[e].x, 1, n, 1);
                else
                    ret += query(g[e].x, 1, n, 1);
            }
            ++ e;
        }
    }
    return ret ;
}
int main(){
    scanf("%d", & T);
    for(int ca = 1; ca <= T; ca ++){ 
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++){
            for(int j =1 ; j <= n; j ++){
                scanf("%d", &grid[i][j]);
            }
        }
        memset(r, 0, sizeof(r));
        memset(c, 0, sizeof(c));
        for(int i = 1; i <= n; i ++){
            for(int j = 1; j <= n; j ++){
                if(grid[i][j]){
                    r[i][j] = r[i][j - 1] + 1;
                    c[i][j] = c[i - 1][j] + 1;
                    u[i][j] = min(r[i][j] , c[i][j]);
                }
            }
        }
        memset(r, 0, sizeof(r));
        memset(c, 0, sizeof(c));
        for(int i = n; i > 0; i --){
            for(int j = n; j > 0; j --){
                if(grid[i][j]){
                    r[i][j] = r[i][j + 1] + 1;
                    c[i][j] = c[i + 1][j] + 1;
                    d[i][j] = min(r[i][j] , c[i][j]);
                }
            }
        }
        int ans = 0;
        for(int i = n; i > 1; -- i){
            ans += solve(i, 1, n - i + 1);
        }
        for(int i = 1; i <= n; i ++){
            ans += solve(1, i, n - i + 1);
        }
        printf("Case %d: %d\n", ca, ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值