HASH表(高效查找)

POJ3349

http://poj.org/problem?id=3349

暴力(TLE)

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include <set>
#include <map>
#include<list>
#include <stack>
#include <queue>
#include <vector>
#include <ctime>

#define ll long long
#define f(i,a,b) for(int i=a;i<=b;i++)
#define m(a,b) memset(a,b,sizeof(a))
#define MAX 0x3f3f3f3f
const ll MOD=1e+9+7;

using namespace std;

bool ISsame(int s1[],int s2[])
{
    int start=0,step=1;
    bool flag=1;
    f(i,0,5){
        if(s2[i]==s1[0]){
            flag=0;
            start=i;
            break;
        }
    }
    if(flag)return false;
    if(s1[1]==s2[(start-1+6)%6])step=-1;
    else if(s1[1]!=s2[(start+1)%6])return false;
    f(i,1,5){
        start+=step;
        if(start>5)start%=6;
        else if(start<0)start=(start+6)%6;
        if(s1[i]!=s2[start])return false;
    }
    return true;
}
bool All(int s[][6],int n)
{
    f(i,0,n-2){
        f(j,i+1,n-1){
            bool pd=0;
            pd=ISsame(s[i],s[j]);
            if(pd)return true;
        }
    }
    return false;
}

int main()
{
    int n;
    cin>>n;
    int s[100010][6];
    m(s,0);
    f(i,0,n-1)
        f(j,0,5){
            scanf("%d",&s[i][j]);
        }
    bool ans=All(s,n);
    if(!ans){
        printf("No two snowflakes are alike.\n");
    }
    else {
        printf("Twin snowflakes found.\n");
    }
    return 0;
}

哈希表进阶

根据具体问题思考如何构造哈希表,从而优化搜索。

AC代码1

#include <iostream>  
#include <cstdio>  
#include <algorithm>  
using namespace std;  

const int N = 1200010;  
const int H = 1200007;  

struct Node  
{  
    int num[6];  
    int next;  
};  
Node node[N];  
int cur;  
int hashTable[H];  

void initHash()  
{  
    cur = 0;  
    for (int i = 0; i < H; ++i) hashTable[i] = -1;  
}  

unsigned int getHash(int* num)  
{  
    unsigned int hash = 0;  
    for (int i = 0; i < 6; ++i)  
    {  
        hash += num[i];  
    }  
    return hash % H;  
}  

bool cmp(int* num1, int* num2)  
{  
    for (int i = 0; i < 6; ++i)  
    {  
        if (num1[i] != num2[i]) return false;  
    }  
    return true;  
}  

void insertHash(int* num, unsigned int h)  
{  
    for (int i = 0; i < 6; ++i) node[cur].num[i] = num[i];  
    node[cur].next = hashTable[h];  
    hashTable[h] = cur;  
    ++cur;  
}  

bool searchHash(int* num)  
{  
    unsigned h = getHash(num);  
    int next = hashTable[h];  
    while (next != -1)  
    {  
        if (cmp(num, node[next].num)) return true;  
        next = node[next].next;  
    }  
    insertHash(num, h);  
    return false;  
}  

int main()  
{  
    int num[2][12];  
    int n;  
    bool twin = false;  
    initHash();  
    scanf("%d", &n);  
    while (n--)  
    {  
        for (int i = 0; i < 6; ++i)   
        {  
            scanf("%d", &num[0][i]);  
            num[0][i + 6] = num[0][i];  
        }  
        if (twin) continue;  
        for (int i = 0; i < 6; ++i)  
        {  
            num[1][i + 6] = num[1][i] = num[0][5 - i];  
        }  
        for (int i = 0; i < 6; ++i)   
        {  
            if (searchHash(num[0] + i) || searchHash(num[1] + i))  
            {  
                twin = true;  
                break;  
            }  
        }  
    }  
    if (twin) printf("Twin snowflakes found.\n");  
    else printf("No two snowflakes are alike.\n");  
    return 0;  
}  

AC代码2


#include<iostream>  
using namespace std;  

const __int64 prime=999983;  // 10n内最大的素数(本题n=10W)  

class  
{  
public:  
    __int64 len[6];  //6瓣叶子的长度  
}leaf[100001];  

typedef class HashTable  
{  
public:  
    __int64 len[6];   //记录6瓣叶子的长度信息  
    HashTable* next;  //用于冲突时开放寻址  

    HashTable()  //Initial  
    {  
        next=0;  
    }  
}Hashtable;  

Hashtable* hash[prime+1];  

/*计算第k个雪花的关键字key*/  

__int64 compute_key(int k)  
{  
    __int64 key=0;  
    for(int i=0;i<6;i++)  
    {  
        key+=(leaf[k].len[i]) % prime;  
        key%=prime;   //利用同余模定理计算key,避免出现大数  
    }  

    return ++key;  //键值后移1位,把key的范围从0~999982变为 1~999983  
}  

/*从顺时针方向判断两片雪花是否相同*/  

bool clockwise(Hashtable* p,int k)  
{  
    for(int j=0;j<6;j++)  //顺时针转动j格  
    {  
        bool flag=true;  
        for(int i=0;i<6;i++)  
            if(leaf[k].len[i] != p->len[(i+j)%6])  
            {  
                flag=false;  
                break;  
            }  
        if(flag)  
            return true;  
    }  
    return false;  
}  

/*从逆时针方向判断两片雪花是否相同*/  

bool counterclockwise(Hashtable* p,int k)  
{  
    for(int j=0;j<6;j++)  //逆时针转动j格  
    {  
        bool flag=true;  
        for(int i=0;i<6;i++)  
            if(leaf[k].len[i] != p->len[(5-i-j+6)%6])  
            {  
                flag=false;  
                break;  
            }  
        if(flag)  
            return true;  
    }  
    return false;  
}  

/*把第k个雪花信息插入HashTable*/  
/*当插入的位置已存在其他雪花信息时,顺便比较*/  

bool insert(int k)  
{  
    __int64 key=compute_key(k);  

    if(!hash[key])  
    {  
        Hashtable* temp=new Hashtable;  

        for(int i=0;i<6;i++)  
            temp->len[i]=leaf[k].len[i];  

        hash[key]=temp;  //保存key对应的地址  
    }  
    else  //地址冲突,开放寻址,顺便比较  
    {  
        Hashtable* temp=hash[key];  

        if(clockwise(temp,k) || counterclockwise(temp,k))  //检查雪花是否相同  
            return true;  

        while(temp->next)    //寻址  
        {  
            temp=temp->next;  

            if(clockwise(temp,k) || counterclockwise(temp,k))  //检查雪花是否相同  
                return true;  
        }  

        temp->next=new Hashtable;    //申请空间,保存新雪花信息  
        for(int i=0;i<6;i++)  
            temp->next->len[i]=leaf[k].len[i];  
    }  
    return false;  
}  

int main(int i,int j)  
{  
    int n;  //雪花数  
    while(cin>>n)  
    {  
        /*Initial*/  

        memset(hash,0,sizeof(hash));  // 0 <-> NULL  

        /*Input*/  

        bool flag=false;  //记录输入过程中是否出现了相同的雪花  
        for(i=1;i<=n;i++)  
        {  
            for(j=0;j<6;j++)  
                scanf("%I64d",&leaf[i].len[j]);  

            /*Hash*/  

            if(!flag)    //当前还没有出现相同的雪花  
                flag=insert(i);  
                         //若出现相同的雪花,则还需后续输入,但不再处理  
        }  

        /*Output*/  

        if(flag)  
            cout<<"Twin snowflakes found."<<endl;  
        else  
            cout<<"No two snowflakes are alike."<<endl;  

    }  
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值