Cuckoo Hashing

Description

One of the most fundamental data structure problems is the dictionary problem: given a set D of words you want to be able to quickly determine if any given query string q is present in the dictionary D or not. Hashing is a well-known solution for the problem. The idea is to create a function h : Σ* → [0..n-1] from all strings to the integer range 0, 1, .., n-1, i.e. you describe a fast deterministic program which takes a string as input and outputs an integer between 0 and n-1. Next you allocate an empty hash table T of size n and for each word w in D, you set T[h(w)] = w. Thus, given a query string q, you only need to calculate h(q) and see if T[h(q)] equals q, to determine if q is in the dictionary. Seems simple enough, but aren't we forgetting something? Of course, what if two words in D map to the same location in the table? This phenomenon, called collision, happens fairly often (remember the Birthday paradox: in a class of 24 pupils there is more than 50% chance that two of them share birthday). On average you will only be able to put roughly √n-sized dictionaries into the table without getting collisions, quite poor space usage!

A stronger variant is Cuckoo Hashing. The idea is to use two hash functions h1 and h2. Thus each string maps to two positions in the table. A query string q is now handled as follows: you compute both h1(q) and h2(q), and if T[h1(q)] = q, or T[h2(q)] = q, you conclude that q is in D. The name "Cuckoo Hashing" stems from the process of creating the table. Initially you have an empty table. You iterate over the words d in D, and insert them one by one. If T[h1(d)] is free, you set T[h1(d)] = d. Otherwise if T[h2(d)] is free, you set T[h2(d)] = d. If both are occupied however, just like the cuckoo with other birds' eggs, you evict the word r in T[h1(d)] and set T[h1(d)] = d. Next you put r back into the table in its alternative place (and if that entry was already occupied you evict that word and move it to its alternative place, and so on). Of course, we may end up in an infinite loop here, in which case we need to rebuild the table with other choices of hash functions. The good news is that this will not happen with great probability even if D contains up to n/2 words!

Input

On the first line of input is a single positive integer 1 ≤ t ≤ 50 specifying the number of test cases to follow. Each test case begins with two positive integers 1 ≤ m ≤ n ≤ 10000 on a line of itself, m telling the number of words in the dictionary and n the size of the hash table in the test case. Next follow m lines of which the ith describes the ith word di in the dictionary D by two non negative integers h1(di) and h2(di) less than n giving the two hash function values of the word di. The two values may be identical.

Output

For each test case there should be exactly one line of output either containing the string "successful hashing" if it is possible to insert all words in the given order into the table, or the string "rehash necessary" if it is impossible.

Sample Input

2
3 3
0 1
1 2
2 0
5 6
2 3
3 1
1 2
5 1
2 5

Sample Output

successful hashing
rehash necessary

裸2SAT

相同值的位置表示为 !A or !B 即可

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define M 40005
using namespace std;
int all,be[],n,m,x,y;
int dfn[M],low[M],instack[M],belong[M],stack[M],stak,curr,num;
int e[M],ne[M],ee[M];
vector<int> vec[]; void add(int x,int y){
e[all]=y;
ee[all]=x;
ne[all]=be[x];
be[x]=all++;
}
void tarjan(int x){
instack[x]=;
stack[++stak]=x;
dfn[x]=low[x]=++curr;
for(int j=be[x];j!=-;j=ne[j])
if(!dfn[e[j]]){
tarjan(e[j]);
if(low[x]>low[e[j]]) low[x]=low[e[j]];
}else if(instack[e[j]]&&low[x]>low[e[j]])
low[x]=low[e[j]];
if(dfn[x]==low[x]){
int j;
++num;
do{
j=stack[stak--];
instack[j]=;
belong[j]=num;
}while(j!=x);
}
}
int solve(){
curr=stak=num=;
memset(dfn,,sizeof(dfn));
memset(low,,sizeof(low));
memset(instack,,sizeof(instack));
for(int i=;i<*n;i++)
if(!dfn[i]) tarjan(i);
bool flag=;
for(int i=;i<n;i++)
if(belong[*i]==belong[*i+]){
flag=;
break;
}
return flag;
}
int main()
{
int tt;
scanf("%d",&tt);
while(tt--)
{
for(int i=; i<=; i++)
vec[i].clear();
all=;
memset(be,-,sizeof(be));
scanf("%d%d",&n,&m);
for(int i=; i<n; i++)
{
scanf("%d%d",&x,&y);
for(vector<int>::iterator it=vec[x].begin(); it!=vec[x].end(); it++)
{
add(*it,*i+);
add(*i,(*it)^);
}
for(vector<int>::iterator it=vec[y].begin(); it!=vec[y].end(); it++)
{
add(*it,*i);
add(*i+,(*it)^);
}
vec[x].push_back(*i);
vec[y].push_back(*i+);
}
// for(int i=0; i<all; i++)
// printf("%d %d\n",ee[i],e[i]);
if(!solve()) printf("successful hashing\n");
else printf("rehash necessary\n");
}
return ;
}

看网上题解也可以用二分图匹配做,顺便写写练手

#include <cstdio>
#include <cstring>
#define M 80005
struct Edge{
int y,ne;
}e[M];
int be[M],pre[M],all,x,y,n,m;
bool vis[M];
void add(int x, int y)
{
e[all].y=y;
e[all].ne=be[x];
be[x]=all++;
}
void init()
{
all=;
memset(be,-,sizeof(be));
memset(pre,-,sizeof(pre));
}
bool dfs(int u)
{
for(int i=be[u]; i!=-; i=e[i].ne)
{
int v=e[i].y;
if(!vis[v])
{
vis[v]=;
if(pre[v]==- || dfs(pre[v]))
{
pre[v]=u;
return ;
}
}
}
return ;
}
int main()
{
int tt;
scanf("%d",&tt);
while(tt--)
{
init();
scanf("%d%d",&n,&m);
for(int i=; i<n; i++)
{
scanf("%d%d",&x,&y);
add(i,x+n);
add(i,y+n);
}
int ans=;
bool flag=;
for(int i=; i<n; i++)
{
memset(vis,,sizeof(vis));
if(!dfs(i))
{
flag=;
break;
}
}
if(flag) printf("successful hashing\n");
else printf("rehash necessary\n");
}
return ;
}

HDU 1672 Cuckoo Hashing的更多相关文章

  1. Cuckoo for Hashing(hash)hunnuoj

    Problem B:Cuckoo for HashingAn integer hash table is a data structure that supports insert, delete a ...

  2. Cuckoo for Hashing_双哈希表

    问题 B: Cuckoo for Hashing 时间限制: 1 Sec  内存限制: 64 MB提交: 24  解决: 12[提交][状态][讨论版] 题目描述 An integer hash ta ...

  3. Cuckoo hash算法分析——其根本思想和bloom filter一致 增加hash函数来解决碰撞 节省了空间但代价是查找次数增加

    基本思想: cuckoo hash是一种解决hash冲突的方法,其目的是使用简单的hash 函数来提高hash table的利用率,同时保证O(1)的查询时间 基本思想是使用2个hash函数来处理碰撞 ...

  4. Locality-sensitive hashing Pr[m(Si) = m(Sj )] = E[JSˆ (Si, Sj )] = JS(Si, Sj )

    A hash function that maps names to integers from 0 to 15. There is a collision between keys "Jo ...

  5. Java数据结构与算法解析(十二)——散列表

    散列表概述 散列表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值. 散列表的思路很简单,如果所有的键都是整数,那么就可以使用一个简单 ...

  6. 《大数据日知录》读书笔记-ch3大数据常用的算法与数据结构

    布隆过滤器(bloom filter,BF): 二进制向量数据结构,时空效率很好,尤其是空间效率极高.作用:检测某个元素在某个巨量集合中存在. 构造: 查询: 不会发生漏判(false negativ ...

  7. CMU Database Systems - Indexes

    这章主要描述索引,即通过什么样的数据结构可以更加快速的查询到数据 介绍Hash Tables,B+tree,SkipList 以及索引的并行访问 Hash Tables hash tables可以实现 ...

  8. 二. 大数据常用的算法和数据结构 <<大数据日知录>> 读书笔记

    基本上是hash实用的各种举例 布隆过滤器 Bloom Filter 常用来检测某个原色是否是巨量数据集合中的成员,优势是节省空间,不会有漏判(已经存在的数据肯定能够查找到),缺点是有误判(不存在的数 ...

  9. Go语言实现布谷鸟过滤器

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/453 介绍 在我们工作中,如果遇到如网页 URL 去重.垃圾邮件识别 ...

随机推荐

  1. Disable keyboard input on Android TimePicker

    try to use: myTimePicker.setDescendantFocusability(TimePicker.FOCUS_BLOCK_DESCENDANTS); to disable f ...

  2. NHibernate 基础

    install-package nhibernate install-package nunit Customer.cs public class Customer { public virtual ...

  3. 以“图片渐入渐出”为例讲述jQuery插件的具体实现

    首先声明,此代码以网友“斯迈欧”原创作为此例的讲解: 在这之前我们先看看我们要做的效果是什么样的: 解析下面的样式:我们要图片在过“一定时间”后自动切换,在右下角处有小方块似数字1,2,3,4,这些数 ...

  4. spring mvc 数据绑定总结

    spring mvc 做web开发时,经常会不知道如何合适绑定页面数据.用惯struts2的朋友更认为spring mvc 绑定数据不如struts2方便(本人最开始也是这么认为),经过一段时间的应用 ...

  5. Oracle 9 - redo和undo

    1.redo redo 有在线redo日志和归档redo日志, 从Oracle 10g开始还新增加了flashback技术. 每个Oracle数据库至少有2个在线重做日志组,循环写. 只有INSERT ...

  6. hibernate的简单学习(第一天)

    sql脚本: -- Create table drop table T_PERSON; create table T_PERSON ( id ) PRIMARY KEY, name ), passwo ...

  7. 【转】Java读取文件方法大全

    本文转自:http://www.cnblogs.com/lovebread/archive/2009/11/23/1609122.html#undefined 目录: 按字节读取文件内容 按字符读取文 ...

  8. 缓存初解(四)---Ibatis的缓存配置+Ehcache

    项目完结,整理一些技术方面的相关收获. 已经记不得EhCacheController这个实现类最早来自于那里了,总之稍加修改后非常有效果,大家就这么用了,感谢最初开源的那位兄弟.这里,主要是做个记录, ...

  9. linux 防火墙iptables简明教程

    前几天微魔部落再次遭受到个别别有用心的攻击者的攻击,顺便给自己充个电,复习了一下linux下常见的防火墙iptables的一些内容,但是无奈网上的很多教程都较为繁琐,本着简明化学习的目的,微魔为大家剔 ...

  10. 汇编debug 截图2