BZOJ 1567 JSOI 2008 Blue Mary的战役地图 二维hash

本文介绍了一种高效的方法来确定两个m*m地图中最大子正方形矩阵的边长。通过将矩阵进行hash操作,并从大到小枚举可能的边长,该算法能够在复杂性较低的情况下解决问题。

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

题目大意:给出两个m*m的地图,问两个地图的最大子正方形矩阵的边长是多大。


思路:先对两个矩阵hash,然后枚举最大长度,从大到小枚举。把第一个矩阵的所有情况插到哈希表中,然后查询第二个矩阵的所有情况。

记住哈希表中的那些数组一定要开大点。。


CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 60
#define RANGE 100100
using namespace std;
const unsigned long long BASE1 = 1333;
const unsigned long long BASE2 = 23333;
const int MO = 999997;
 
int m;
unsigned long long hash[MAX][MAX],_hash[MAX][MAX];
unsigned long long pow1[MAX],pow2[MAX];
 
struct HashSet{
    int head[MO],total;
    int next[RANGE];
    unsigned long long hash[RANGE];
     
    bool Check(unsigned long long h) {
        int x = h % MO;
        for(int i = head[x]; i; i = next[i])
            if(hash[i] == h)
                return true;
        return false;
    }
    void Insert(unsigned long long h) {
        int x = h % MO;
        next[++total] = head[x];
        hash[total] = h;
        head[x] = total;
    }
}set;
 
int main()
{
    cin >> m;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%lld",&hash[i][j]);
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j)
            scanf("%lld",&_hash[i][j]);
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j) {
            hash[i][j] += hash[i - 1][j] * BASE1;
            _hash[i][j] += _hash[i - 1][j] * BASE1;
        }
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= m; ++j) {
            hash[i][j] += hash[i][j - 1] * BASE2;
            _hash[i][j] += _hash[i][j - 1] * BASE2;
        }
    pow1[0] = pow2[0] = 1;
    for(int i = 1; i <= m; ++i)
        pow1[i] = pow1[i - 1] * BASE1,pow2[i] = pow2[i - 1] * BASE2;
    int ans;
    for(ans = m; ans; --ans) {
        for(int i = ans; i <= m; ++i)
            for(int j = ans; j <= m; ++j) {
                unsigned long long h = hash[i][j];
                h -= hash[i - ans][j] * pow1[ans];
                h -= hash[i][j - ans] * pow2[ans];
                h += hash[i - ans][j - ans] * pow1[ans] * pow2[ans];
                set.Insert(h);
            }
        for(int i = ans; i <= m; ++i)
            for(int j = ans; j <= m; ++j) {
                unsigned long long h = _hash[i][j];
                h -= _hash[i - ans][j] * pow1[ans];
                h -= _hash[i][j - ans] * pow2[ans];
                h += _hash[i - ans][j - ans] * pow1[ans] * pow2[ans];
                if(set.Check(h)) {
                    cout << ans << endl;
                    return 0;
                }
            }
    }
    cout << 0 << endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值