[JSOI2008]Blue Mary的战役地图 (二维Hash)

[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;
}
原文地址:https://www.cnblogs.com/DZN2004/p/13404140.html