CSU 1216 异或最大值 01trie

题目:

https://vjudge.net/problem/CSU-1216

题意:

给定一些数,求这些数中两个数的异或值最大的那个值

Input
多组数据。第一行为数字个数n,1 <= n <= 10 ^ 5。接下来n行每行一个32位有符号非负整数。

Output
任意两数最大异或值

思路:

最暴力的方法是枚举两个数,这样显然不可行,当枚举 x 时,怎么找到另一个数字 y 使得 xy 最大呢?可以发现,应该是分解成二进制然后从最高位开始对比,其中有一些数字和 x 在当前位上是相同的,另外一些是不同的,这时候我们应该对数字进行选择,显然应该选取不同的,相同的都扔掉,然后往下一位对比,当然如果全相同的话,就不能扔了,也往下一位对比,一直到末尾。我们可以用字典树实现这个选择功能,这样就比较简单了

#include 
#include 
#include 
#include 

using namespace std;

const int N = 100000 + 10, M = 2;
struct node
{
    node *next[M];
    void init()
    {
        memset(next, 0, sizeof next);
    }
}trie[N*25], *root;
int tot;
int len = 31;
int a[N];
node* new_node()
{
    trie[tot].init();
    return trie + tot++;
}
void trie_init()
{
    tot = 0;
    root = new_node();
}
void trie_insert(int val)
{
    node *p = root;
    for(int i = len-1; i >= 0; i--)
    {
        int j = 1 & (val>>i);
        if(p->next[j] == NULL) p->next[j] = new_node();
        p = p->next[j];
    }
}
int trie_query(int val)
{
    node *p = root;
    int ans = 0;
    for(int i = len-1; i >= 0; i--)
    {
        int j = ! (1 & (val>>i));//j是val在当前位置上的相反数,即val在当前位是0,则j=1,否则反之
        if(p->next[j] != NULL)//相反数存在,则异或后当前位的二进制为1
        {
            p = p->next[j];
            ans = ans * 2 + 1;
        }
        else //否则为0
        {
            p = p->next[!j];
            ans = ans * 2 + 0;
        }
    }
    return ans;
}
int main()
{
    int n;
    while(~ scanf("%d", &n))
    {
        trie_init();
        int ans = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            trie_insert(a[i]);
            ans = max(ans, trie_query(a[i]));
        }
        printf("%d\n", ans);
    }
    return 0;
}

你可能感兴趣的:(字典树)