BZOJ 1567: [JSOI2008]Blue Mary的战役地图 Hash+set

[Submit][Status][Discuss]
Description
Blue Mary最近迷上了玩Starcraft(星际争霸) 的RPG游戏。她正在设法寻找更多的战役地图以进一步提高自己的水平。 由于Blue Mary的技术已经达到了一定的高度,因此,对于用同一种打法能够通过的战役地图,她只需要玩一张,她就能了解这一类战役的打法,然后她就没有兴趣再玩儿这一类地图了。而网上流传的地图有很多都是属于同一种打法,因此Blue Mary需要你写一个程序,来帮助她判断哪些地图是属于同一类的。 具体来说,Blue Mary已经将战役地图编码为n*n的矩阵,矩阵的每个格子里面是一个32位(有符号)正整数。对于两个矩阵,他们的相似程度定义为他们的最大公共正方形矩阵的边长。两个矩阵的相似程度越大,这两张战役地图就越有可能是属于同一类的。
Input
第一行包含一个正整数n。 以下n行,每行包含n个正整数,表示第一张战役地图的代表矩阵。 再以下n行,每行包含n个正整数,表示第二张战役地图的代表矩阵。
Output
仅包含一行。这一行仅有一个正整数,表示这两个矩阵的相似程度。
Sample Input
3

1 2 3

4 5 6

7 8 9

5 6 7

8 9 1

2 3 4

Sample Output
2

HINT

样例解释:

子矩阵:
5 6
8 9
为两个地图的最大公共矩阵

约定:
n<=50

解法:先对两个矩阵hash,然后枚举最大长度,从大到小枚举。把第一个矩阵的所有情况插到哈希表中,然后查询第二个矩阵的所有情况,我用的set,也可以用vector然后去二分check。

//BZOJ 1567

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long uLL;
const int maxn = 60;
const int mod = 999997;
const uLL BASE1 = 1333;
const uLL BASE2 = 23333;
int m;
uLL hash1[maxn][maxn], hash2[maxn][maxn];
uLL base1[maxn], base2[maxn];

set <uLL> s;

void input()
{
    scanf("%d", &m);
    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            scanf("%lld", &hash1[i][j]);
        }
    }
    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            scanf("%d", &hash2[i][j]);
        }
    }
    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            hash1[i][j] += hash1[i-1][j]*BASE1;
            hash2[i][j] += hash2[i-1][j]*BASE1;
        }
    }
    for(int i = 1; i <= m; i++){
        for(int j = 1; j <= m; j++){
            hash1[i][j] += hash1[i][j-1]*BASE2;
            hash2[i][j] += hash2[i][j-1]*BASE2;
        }
    }
    base1[0] = base2[0] = 1;
    for(int i = 1; i <= m; i++){
        base1[i] = base1[i-1]*BASE1;
        base2[i] = base2[i-1]*BASE2;
    }
}

void work()
{
    s.clear();
    int ans, flag  = 0;
    for(ans = m; ans; ans--){
        for(int i = ans; i <= m; i++){
            for(int j = ans; j <= m; j++){
                uLL h = hash1[i][j];
                h -= hash1[i-ans][j]*base1[ans];
                h -= hash1[i][j-ans]*base2[ans];
                h += hash1[i-ans][j-ans]*base1[ans]*base2[ans];
                //h %= mod;
                s.insert(h);
            }
        }
        for(int i = ans; i <= m; i++){
            for(int j = ans; j <= m; j++){
                uLL h = hash2[i][j];
                h -= hash2[i-ans][j]*base1[ans];
                h -= hash2[i][j-ans]*base2[ans];
                h += hash2[i-ans][j-ans]*base1[ans]*base2[ans];
                //h %= mod;
                if(s.find(h) != s.end()){
                    flag = 1;
                    break;
                }
            }
            if(flag) break;
        }
        if(flag) break;
    }
    if(flag) cout << ans << endl;
    else cout << 0 << endl;
}

void output()
{

}

int main()
{
    input();
    work();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值