18907 雪花雪花雪花

一道历史悠久且经典的哈希法例题,哈希法的题目实在是比较少。

暴力枚举的话复杂度显然是O(n^{2})是,实际上,如果能提前计算出每个雪花的特性,那么属性不相同的雪花就无需进行比较。相当于我们将雪花分成若干个小组(想想世界杯为什么要分小组赛,而不是32个队都两两比一次),每个小组内部两两比较,这样的话复杂度就会降低。假设我们能把n个数组分成X组,每组数据估算为n/X个,组内两两比较。那么算法复杂度为O((\frac{n}{x})^{2}+(\frac{n}{x})^{2}+(\frac{n}{x})^{2}.......)=O(\frac{n^{2}}{x}),当X比较大时复杂度会有明显的降低。

这样分组使用的方法(哈希函数)就很重要,既要保障X的值稍大一点,又要保证相同的雪花一定分在同一组。最简单的就是把雪花的6个角值求和(也可以求乘积),再对X求余,X取值可以设定为某个质数,如果设定为997,那么雪花被分成997组,同理也可以设定为9997或其他值,读者可以尝试把X设置比较小的值,如97看看会否超时。

计算两个雪花是否一致只能用暴力算法,用环处理或者直接枚举位置都可行,此处是直接枚举正反两方向。

#include <iostream>
#include<vector>
typedef long long ll;
using namespace std;
ll n,a[100005][7],mod=99997;
vector<int>v[100010];/**< 动态二维数组v用于存储哈希表,哈希值为X的元素存储在v[X]中,实际上是教材上的链地址法,但是链表太麻烦了,用这种写法可以完美取代链表*/
int hs(int i) /**< 哈希函数 */
{
    return (a[i][1]%mod+a[i][2]%mod+a[i][3]%mod+a[i][4]%mod+a[i][5]%mod+a[i][0]%mod)%mod;
}
bool check(int x,int y)
{
    int i,j;
   for(i=0; i<6; i++)/**< 正反两个方向比较雪花 */
        if(a[x][0]==a[y][i]&&a[x][1]==a[y][(i+1)%6]&&a[x][2]==a[y][(i+2)%6]&&a[x][3]==a[y][(i+3)%6]
                &&a[x][4]==a[y][(i+4)%6]&&a[x][5]==a[y][(i+5)%6])
            return true;
    for(i=0; i<6; i++)
        if(a[x][0]==a[y][i]&&a[x][1]==a[y][(i+5)%6]&&a[x][2]==a[y][(i+4)%6]&&a[x][3]==a[y][(i+3)%6]
                &&a[x][4]==a[y][(i+2)%6]&&a[x][5]==a[y][(i+1)%6])
            return true;
    return false;
}
int main()
{
    int i,j,k,l;
    cin>>n;
    for(i=1; i<=n; i++)
    {
        for(j=0; j<6; j++)
            scanf("%d",&a[i][j]);
        int t=hs(i);/**< 计算哈希值t后,下面循环访问v[t],和之前出现过,且哈希值同样是t的雪花做比较 */
        for(j=0; j<v[t].size(); j++)
            if(check1(i,v[t][j]))
            {
                cout<<"Twin snowflakes found.";
                return 0;
            }
        v[t].push_back(i);/**< 比较结束,将i加入对应的哈希表, */
    }
    cout<<"No two snowflakes are alike.";
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值