题目大意:给出两个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;
}