• 【POJ3349】Snowflake Snow Snowflakes(哈希表判重,维护一个集合)


    problem

    • 有n片雪花,每片有6个脚,每个脚有一个长度。
    • 两片雪花是一样的当且仅当每个脚的长度顺序都一样(顺逆时针和开始位置不管)
    • 求n片雪花中是否有一样的雪花。

    solution

    维护一个哈希表

    • 定义Hash(a1,a2,..a6) = (sum(a1..a6)+ji(a1..a6))%P
    • 对于两片雪花,当且仅当他们的hash值相同时他们相同.期望复杂度O(N(N/P)^2)

    codes

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    const int maxn = 100010, P = 99991;
    
    int n, snow[maxn][6];
    bool equal(int *a, int *b){
        for(int i = 0; i < 6; i++){
            for(int j = 0; j < 6; j++){
                int eq = 1;
                for(int k = 0; k < 6; k++)
                    if(a[(i+k)%6] != b[(j+k)%6])eq = 0;
                if(eq)return 1;
                eq = 1;
                for(int k = 0; k < 6; k++)
                    if(a[(i+k)%6] != b[(j-k+6)%6])eq = 0;
                if(eq)return 1;
            }
        }
        return 0;
    }
    
    int tot, head[maxn], Next[maxn];
    int H(int *a){
        int sum = 0, mul = 1;
        for(int i = 0; i < 6; i++){
            sum = (sum+a[i])%P;
            mul = (long long)mul*a[i]%P;
        }
        return (sum+mul)%P;
    }
    bool insert(int *a){
        int key = H(a);
        for(int i = head[key]; i; i = Next[i])//近似O(1)
            if(equal(snow[i],a))return 0;
        tot++;
        memcpy(snow[tot],a,6*sizeof(int));
        Next[tot] = head[key];
        head[key] = tot;
        return 1;
    }
    
    int main(){
        int n;  cin>>n;
        for(int i = 1; i <= n; i++){
            int a[10];
            for(int i = 0; i < 6; i++)scanf("%d",&a[i]);
            if(!insert(a)){//如果已有,插入失败
                printf("Twin snowflakes found.
    ");
                return 0;
            }
        }
        printf("No two snowflakes are alike.
    ");
        return 0;
    }

    Hash表

    介绍

    1、哈希算法通过一个哈希函数H,将一种数据(包括字符串,数组)转化为能用变量表示,或是直接可作为数组下标的数(这样就可以O(1)判断是否存在)。
    2、通过哈希函数转化的数值称为哈希值。
    3、因为值域变简单,范围变小,可能造成两个原始信息被映射为相同值,称之为冲突。

    具体

    1、对于哈希函数,我们有以下几种常见的构造方法:
    (a)除余法
    选择一个适当的模数b,令H(key) = key%b。
    b一般选择比较大的质数,减少冲突的几率。
    (b)乘积取整法
    选择一个(0,1)中的实数A, 令H(key) = M(A*key%1)。
    即,key*A取小数部分乘以哈希表大小M再向下取整。
    (c)基数转换法
    将key看做为另一种进制的数,把他转为对应10进制数,再用除余法对他取余。
    字符串哈希一般采用的方法。

    2、对于冲突,我们一般采用开散列的方式解决:
    对每一个哈希值开一个链表(相当于邻接表),把所有等同于同一哈希值的数字都记录下来,查找的时候遍历对应的链表。
    这样期望复杂度为O(1),实际可能变大,但也是常数级。

  • 相关阅读:
    [原]poj-2680-Choose the best route-dijkstra(基础最短路)
    [转]c/c++输入函数
    [原]poj-2524(裸并查集)
    [原]poj-1611-The Suspects(水并查集)
    ccnu-线段树-简单的区间更新(三题)
    团队博客(3)
    个人NABCD
    团队博客(2)
    团队博客(1)
    课堂练习:返回一个二维数组中最大子数组的和
  • 原文地址:https://www.cnblogs.com/gwj1314/p/10200117.html
Copyright © 2020-2023  润新知