二维hash(Uva 12886)

本文介绍了一种使用矩阵Hash算法在大矩阵中查找特定小矩阵的方法。通过定义横纵方向的Hash值并采用不同种子值避免冲突,实现了高效精确匹配。文章提供了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=88791(题目连接)

这道道题就是让你在大矩阵里找小矩阵,用矩阵hash

用矩阵hash之前我们先定义下面这些玩意

hash1[][]记录横列的的hash值

hash2[][]记录纵向的hahs值

hash表示小矩阵的hash值

定义两个种子常数

const ULL seed1=10000007;
const ULL seed2=100000007;

两个种子的值不能相同,因为有时横向和纵向的hash值会相同。所以要用不同的种子值,orz= =

先求小矩阵的的hash值

 1 ULL get_hash()
 2 {
 3      ULL t=0;
 4     for(int i=0;i<x;i++)
 5     {
 6          ULL cnt=0;
 7          for(int j=0;j<y;j++)
 8             cnt=cnt*seed1+s[i][j];//
 9          t=t*seed2+cnt;
10     }
11     return t;
12 }

然后在大矩阵中构造小矩阵。。。。。想见代码吧= =

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define maxn 2005
using namespace std;
typedef unsigned long long ULL;
const ULL seed1=10000007;
const ULL seed2=100000007;
char s[maxn][maxn];
char ch[maxn][maxn];
ULL hash1[maxn][maxn];
ULL hash2[maxn][maxn];
ULL hash;
ULL ans;
int x,y,n,m;
ULL get_hash()
{
     ULL t=0;
    for(int i=0;i<x;i++)
    {
         ULL cnt=0;
         for(int j=0;j<y;j++)
            cnt=cnt*seed1+s[i][j];
         t=t*seed2+cnt;
    }
    return t;
}
void count_num()
{
    ULL c=1;
    for(int i=0;i<y;i++)
    c=c*seed1; //等会求构造矩阵的hash值需要减去第j-y位置的字符的hash值,所以要进行这步。。。
    for(int i=0;i<n;i++)
    {
        ULL cnt=0;
        for(int j=0;j<y;j++)
            cnt=cnt*seed1+ch[i][j];
        hash1[i][y-1]=cnt;
        for(int j=y;j<m;j++)
        {
            hash1[i][j]=hash1[i][j-1]*seed1-ch[i][j-y]*c+ch[i][j];//求横列的hash值
        }
    }
     c=1;
     for(int i=0;i<x;i++)
        c=c*seed2;
     for(int i=y-1;i<m;i++)
     {
         ULL a=0;
         for(int j=0;j<x;j++)
             a=a*seed2+hash1[j][i];//这里因为将横列的的字符用他的hash值代替= =
         hash2[x-1][i]=a;
         if(a==hash)
            ans++;
         for(int j=x;j<n;j++)
         {
             hash2[j][i]=hash2[j-1][i]*seed2-hash1[j-x][i]*c+hash1[j][i];
                if(hash2[j][i]==hash)//相同ans++
                ans++;
         }
     }
}
int main()
{
    while(scanf("%d %d %d %d",&x,&y,&n,&m)!=EOF)
    {
        getchar();
        memset(hash1,0,sizeof(hash1));
        memset(hash2,0,sizeof(hash2));
        for(int i=0;i<x;i++)
            scanf("%s",s[i]);
        for(int i=0;i<n;i++)
            scanf("%s",ch[i]);  
        hash=get_hash();
        ans=0;
        count_num();
        printf("%llu\n",ans);
    }
    return 0;
}

 

二维哈希封装模板通常在需要将二维数据结构与哈希表功能结合起来的场景下使用,尤其是在需要快速查找、插入和删除元素的情况下。这种结构可以大大提高数据处理效率。 ### 思想概述 二维哈希封装模板的基本思想是创建一个类,该类内部包含一个哈希表,用于存储键值对,并允许通过两个维度的索引来访问这些键值对。这种设计使得用户可以通过一组有序的键(例如坐标)来直接定位到特定的数据位置。 ### 实现细节 在实现过程中,关键在于如何设计哈希函数,使其能够有效地利用空间并减少碰撞(即不同的键映射到相同的哈希值)。常见的做法包括: 1. **哈希函数**:设计一种算法,将二维坐标转换为唯一的整数,作为哈希表的键。这通常涉及到计算两个坐标值的某种组合,比如简单相加、乘法或其他数学操作,以及可能的模运算,以确保结果保持在哈希表的范围内。 2. **负载因子管理**:为了保持良好的性能,通常需要控制哈希表的负载因子(即已使用的条目占总容量的比例),并在达到某个阈值时动态调整哈希表的大小。 3. **冲突解决策略**:当不同的键映射到同一哈希值时,需要有机制来解决冲突,如链地址法、开放寻址等。 4. **封装**:提供方便的操作接口,允许用户以直观的方式添加、查询和移除元素,而不需要深入了解底层的哈希实现细节。 ### 示例应用 二维哈希表可以应用于多种场景,如地图搜索、游戏中的网格管理、数据库索引优化等。例如,在游戏中,每个玩家的位置可以用二维坐标表示,使用二维哈希表可以高效地更新和查询玩家的位置信息。 ### 相关问题: 1. 为什么选择特定的哈希函数来计算二维坐标? 2. 在什么情况下会考虑增加哈希表的大小? 3. 二维哈希表如何处理不同维度之间的关联和独立性问题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值