zoukankan      html  css  js  c++  java
  • Blue Mary的战役地图——Hash表

    Blue Mary的战役地图

    题目描述

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

    输入格式

    • 输入文件的第一行包含一个正整数 n。
    • 以下 n 行,每行包含 n 个正整数,表示第一张战役地图的代表矩阵。
    • 再以下 n 行,每行包含 n 个正整数,表示第二张战役地图的代表矩阵。

    输出格式

    • 输出文件仅包含一行。这一行仅有一个正整数,表示这两个矩阵的相似程度。

    样例输入

    3
    1 2 3
    4 5 6
    7 8 9
    5 6 7
    8 9 1
    2 3 4
    

    样例输出

    2
    

    数据范围与提示

    • 子矩阵:

      5 6
      8 9

      为两个地图的最大公共矩阵

      • 对于 100% 的数据 (1le nle 100)

    Solve

    • 题目大意

      • 找到最大公共子矩阵(必须为正方形)。
    • 写法类似于Hash表。

    • Hash表是将同一类的放进一个链表中,减少查找的次数。

    • 这道题可以直接将矩阵内的和当做分类的标准,这个可以通过矩阵前缀和进行 (O(n^2)) 的预处理,可以(O(1)) 的计算出来,将矩阵和相同的放在一条链中,

    • 注意事项

      1. Hash表的数量由子矩阵的数量确定,一个 n×n 的矩阵有 n×n×n 个子矩阵,head数组和链表结构体开 (n^3) 的就够的,模数就取数组能开下的范围内最大的质数就可以了。
      2. 本写法比较用于随机数据,因为这样分布到每条链上的个数都会很少,而对于特殊构造的数据,时间复杂度可能会退化到 (O(n^7)),但过本题是没问题的。
    • 详细看代码注释。

    Code

    #include <cstdio>
    #define ll long long
    using namespace std;
    const int N = 105, M = 1157621;//M是105*105*105中最大质数
    const int N3 = N*N*N;
    int n, a[N][N], b[N][N];
    ll s[2][N][N];//存前缀和
    struct Node {
        int k, x, y, next;
    }h[N3];//链表
    int head[N3], tot;
    int Ha(int k, int x, int y, int p) {//求Hash值
        x--, y--;
        return (int)(s[p][x+k][y+k] - s[p][x][y+k] - s[p][x+k][y] + s[p][x][y]) % M;//通过前缀和求期间和
    }
    void Add(int k, int i, int j) {//在Hash表中添加,挺像加边操作
        int ha = Ha(k, i, j, 0);
        h[++tot] = (Node) {k, i, j, head[ha]};
        head[ha] = tot;
    }
    bool Judge(int n, int k, int x, int y) {//判断是否相同
        if (h[n].k != k) return 0;
        for (int i = 0; i < k; ++i)
            for (int j = 0; j < k; ++j)
                if (a[h[n].x+i][h[n].y+j] != b[x+i][y+j])
                    return 0;
        return 1;
    }
    bool Find(int k, int x, int y) {
        int ha = Ha(k, x, y, 1);
        if (!head[ha]) return 0;
        for (int i = head[ha]; i; i = h[i].next)//遍历这条链
            if (Judge(i, k, x, y)) return 1;
        return 0;
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                scanf("%d", &a[i][j]), 
                s[0][i][j] = s[0][i-1][j] + s[0][i][j-1] - s[0][i-1][j-1] + a[i][j];
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                scanf("%d", &b[i][j]),
                s[1][i][j] = s[1][i-1][j] + s[1][i][j-1] - s[1][i-1][j-1] + b[i][j];
        for (int k = 1; k <= n; ++k)
            for (int i = 1; i + k - 1 <= n; ++i)
                for (int j = 1; j + k - 1 <= n; ++j)
                    Add(k, i, j);//将第一个图的所有子矩阵加入
        for (int k = n; k >= 1; --k)//从大到小枚举,找到了直接输出,这个for也可以二分
            for (int i = 1; i + k - 1 <= n; ++i)
                for (int j = 1; j + k - 1 <= n; ++j)
                    if (Find(k, i, j)) return printf("%d
    ", k), 0;
        puts("0");
        return 0;
    }
    
  • 相关阅读:
    Unity Notes调制粒子系统的颗粒的最大数目
    Swift编程语言学习2.1——基础运营商(在)
    JavaScript语言基础知识6
    算法题:合并两个有序列表
    DDFT
    Java For循环效率试验
    Delphi ORD
    Delphi TcxTreeList 节点添加图片
    SQL Server 除法 不起作用的问题
    Delphi 继承基类的窗体,并显示基类的控件操作。
  • 原文地址:https://www.cnblogs.com/shawk/p/13405596.html
Copyright © 2011-2022 走看看