真让我找到有关布谷鸟哈希的题了
布谷鸟哈希是一种用于哈希表的哈希策略,其主要特点是建立两个或更多哈希桶,在哈希冲突时踢出原键值,在冲突地址插入新键值,原键值插入另一个桶中。我写了一篇文章以详细介绍:点击跳转。
要想做这道题,就得先理清布谷鸟哈希的工作流程。
双哈希函数的布谷鸟哈希表可以用一张有向图来描述:点表示一个地址
其中方框表示地址,圆表示键值,方框中含圆表示该地址已有键值存储,方框中无圆表示该地址为空,圆不在方框内表示待插入。
我们即将插入
我同时对边进行了染色处理,红色边表示这条边经过了反转,绿色表示我们即将沿着这条边存储进一个位置。
随后是
最后,在踢出
随后
我们将
那么这对我们要做的这道题有什么帮助?
没错,我们可以建图!
按理来说,不同的哈希冲突策略都可以建图,但是布谷鸟哈希建出来的图有一个很明显的性质:哈希成功的情况当且仅当对于图中每一个极大的联通块都有边数不大于点数。
必要性显然,下证充分性。
:::info[证明]
设有哈希函数
:::
因为我们不模拟哈希冲突,所以建无向图就够了。
代码环节。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
mt19937 myrand(time(0));
inline ll read(){
ll x=0,w=1;
char ch=0;
while(ch<'0'||ch>'9'){
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*w;
}
void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
static int sta[40];
int top=0;
do{
sta[top++]=x%10,x/=10;
}while(x);
while(top)putchar(sta[--top]+'0');
}
const int N=1e4+5;
int n,m,cnt1,cnt2;
bitset<N>vis1,vis2;
vector<pair<int,int>>e[N];
void dfs(int u) {
vis1[u]=1;
++cnt1;
for (auto P:e[u]) {
int v=P.first,id=P.second;
if (vis2[id])continue;
vis2[id]=1;
++cnt2;
if(!vis1[v])dfs(v);
}
}
inline void work() {
m=read();n=read();
for (int i=1;i<=n;i++)e[i].clear();
vis1.reset();
vis2.reset();
for (int i=1;i<=m;i++) {
int u=read()+1;
int v=read()+1;
e[u].emplace_back(v,i);
e[v].emplace_back(u,i);
}
for(int i=1;i<=n;i++){
if(!vis1[i]){
cnt1=cnt2=0;
dfs(i);
if(cnt2>cnt1){
puts("rehash necessary");
return;
}
}
}
puts("successful hashing");
}
int t;
int main(){
t=read();
while (t--)work();
return 0;
}
AC 链接。