zoukankan      html  css  js  c++  java
  • HDU 1672 Cuckoo Hashing

    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[20005],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[10005];
    
    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]=1;
        stack[++stak]=x;
        dfn[x]=low[x]=++curr;
        for(int j=be[x];j!=-1;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]=0;
                belong[j]=num;
            }while(j!=x);
        }
    }
    int solve(){
        curr=stak=num=0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(instack,0,sizeof(instack));
        for(int i=0;i<2*n;i++)
            if(!dfn[i]) tarjan(i);
        bool flag=0;
        for(int i=0;i<n;i++)
            if(belong[2*i]==belong[2*i+1]){
                flag=1;
                break;
            }
        return flag;
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            for(int i=0; i<=10000; i++)
                vec[i].clear();
            all=0;
            memset(be,-1,sizeof(be));
            scanf("%d%d",&n,&m);
            for(int i=0; i<n; i++)
            {
                scanf("%d%d",&x,&y);
                for(vector<int>::iterator it=vec[x].begin(); it!=vec[x].end(); it++)
                {
                    add(*it,2*i+1);
                    add(2*i,(*it)^1);
                }
                for(vector<int>::iterator it=vec[y].begin(); it!=vec[y].end(); it++)
                {
                    add(*it,2*i);
                    add(2*i+1,(*it)^1);
                }
                vec[x].push_back(2*i);
                vec[y].push_back(2*i+1);
            }
            // for(int i=0; i<all; i++)
            //     printf("%d %d
    ",ee[i],e[i]);
            if(!solve()) printf("successful hashing
    ");
                else printf("rehash necessary
    ");
        }
        return 0;
    }
    View Code

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

    #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=0;
        memset(be,-1,sizeof(be));
        memset(pre,-1,sizeof(pre));
    }
    bool dfs(int u)
    {
        for(int i=be[u]; i!=-1; i=e[i].ne)
        {
            int v=e[i].y;
            if(!vis[v])
            {
                vis[v]=1;
                if(pre[v]==-1 || dfs(pre[v]))
                {
                    pre[v]=u;
                    return 1;
                }
            }
        }
        return 0;
    }
    int main()
    {
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            init();
            scanf("%d%d",&n,&m);
            for(int i=0; i<n; i++)
            {
                scanf("%d%d",&x,&y);
                add(i,x+n);
                add(i,y+n);
            }
            int ans=0;
            bool flag=1;
            for(int i=0; i<n; i++)
            {
                memset(vis,0,sizeof(vis));
                if(!dfs(i))
                {
                    flag=0;
                    break;
                }
            }
            if(flag) printf("successful hashing
    ");
            else printf("rehash necessary
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    <%# %>数据绑定
    BUTTON在界面上位置的移动
    双击树节点,将其添加到ListBar中
    关于魔方的故事 来源:未知
    xml做TreeView
    子父窗体
    word中,文档更改标记
    Ogre中实现 几何面正反面不同纹理贴图
    利用模板化的空闲块列表克服内存碎片问题
    window平台下 实时高效打印其他窗口,并作为D3D纹理使用
  • 原文地址:https://www.cnblogs.com/Mathics/p/3895410.html
Copyright © 2011-2022 走看看