[JSOI2008]Blue Mary的战役地图
题目链接
题目
Blue Mary最近迷上了玩Starcraft(星际争霸) 的RPG游戏。她正在设法寻找更多的战役地图以进一步提高自己的水平。
由于Blue Mary的技术已经达到了一定的高度,因此,对于用同一种打法能够通过的战役地图,她只需要玩一张,她就能了解这一类战役的打法,然后她就没有兴趣再玩儿这一类地图了。而网上流传的地图有很多都是属于同一种打法,因此Blue Mary需要你写一个程序,来帮助她判断哪些地图是属于同一类的。
具体来说,Blue Mary已经将战役地图编码为n*n的矩阵,矩阵的每个格子里面是一个32位(有符号)正整数。对于两个矩阵,他们的相似程度定义为他们的最大公共正方形矩阵的边长。两个矩阵的相似程度越大,这两张战役地图就越有可能是属于同一类的。(n <= 100)
分析
这题可以直接暴力水过,但是通过这道题可以学习一下二维Hash。
我们可以先把一行缩为一个点,再缩列。
代码 :
for(int i = 1; i <= n; ++i) //行
for(int j = 1; j <= n; ++j)
cin >> a[i][j], a[i][j] = (a[i][j-1]*rowbase + a[i][j]);
for(int i = 1; i <= n; ++i) // 列
for(int j = 1; j <= n; ++j)
a[i][j] = (a[i][j] + a[i-1][j]*calbase);
然后开个 map 存一下每个值就行了。
还有一个重点就是计算矩阵Hash和。
int calc1(int x, int y, int d) {
return a[x][y] - a[x-d][y]*cal[d] - a[x][y-d]*row[d] + a[x-d][y-d]*cal[d]*row[d];
}
int calc2(int x, int y, int d) {
return b[x][y] - b[x-d][y]*cal[d] - b[x][y-d]*row[d] + b[x-d][y-d]*cal[d]*row[d];
}
这个可以类比一维hash区间求和。
然后就是完整代码了 :
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N = 105, rowbase = 11, calbase = 13;
int a[N][N], b[N][N], row[N], cal[N], n;
map<int, bool> p;
int calc1(int x, int y, int d) {
return a[x][y] - a[x-d][y]*cal[d] - a[x][y-d]*row[d] + a[x-d][y-d]*cal[d]*row[d];
}
int calc2(int x, int y, int d) {
return b[x][y] - b[x-d][y]*cal[d] - b[x][y-d]*row[d] + b[x-d][y-d]*cal[d]*row[d];
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
cin >> n;
row[0] = cal[0] = 1;
for(int i = 1; i <= n; ++i) row[i] = row[i-1]*rowbase, cal[i] = cal[i-1]*calbase;
for(int i = 1; i <= n; ++i) //行
for(int j = 1; j <= n; ++j)
cin >> a[i][j], a[i][j] = (a[i][j-1]*rowbase + a[i][j]);
for(int i = 1; i <= n; ++i) // 列
for(int j = 1; j <= n; ++j)
a[i][j] = (a[i][j] + a[i-1][j]*calbase);
for(int d = 0; d <= n; ++d)
for(int i = d; i <= n; ++i)
for(int j = d; j <= n; ++j)
p[calc1(i, j, d)] = 1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
cin >> b[i][j], b[i][j] = (b[i][j-1]*rowbase + b[i][j]);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
b[i][j] = (b[i][j] + b[i-1][j]*calbase);
for(int d = n; d >= 0; --d)
for(int i = d; i <= n; ++i)
for(int j = d; j <= n; ++j)
if(p.find(calc2(i, j, d)) != p.end())
return cout << d, 0;
return 0;
}