AcWing 143. 最大异或对 (01Trie树 贪心)

题目描述

原题链接

AcWing 143. 最大异或对 (01Trie树 贪心)_第1张图片

分析

推荐参考Y总视频讲解

暴力做法 O ( n 2 ) : O(n^2): O(n2): 依次选出 A 1 , A 2 . . . . A n A_1,A_2....A_n A1,A2....An, 与其余的数进行异或 & \& &运算, 求出最大值
优化暴力做法: 是否存在一种方法, 可以快速选出与 A 1 A_1 A1异或值最大的数 ? ? ?
根据异或的性质, 我们可以利用贪心的思想:
从最高位开始, 每次优先选出与 A 1 A_1 A1最高位不同的那些数, 因为这样异或后最高位一定是 1 1 1(若都相同,则选相同的, 异或后,最高位为 0 0 0)
再从选出的那些数中, 优先选出与 A 1 A_1 A1次高位不同的那些数, 得到局部的最优解
依次筛选到最后一位,得到答案
上述过程,可以用01trie树来实现.

实现

#include 
#include 
#include 
using namespace std;
const int N = 1e5 + 9;
int a[N];
int trie[30*N][2]; // trie[最多有多少节点数][边权是0或1] = 当前节点的下标
int n, ans, index;
void insert(int val)
{
    int p = 0;
    for(int i=30; i>=0; i--) // val最多有31位
    {
        if(!trie[p][val >> i & 1]) trie[p][val >> i & 1] = ++ index; // 新建节点
        p = trie[p][val >> i & 1]; // 访问下一个节点
    }
}
int query(int val) // 查询与val异或得到的最大结果
{
    int p = 0; // 当前访问的节点
    int sum = 0; // 在遍历trie树的同时, 根据边权得到最大结果
    for(int i=30; i>=0; i--) // val最多有30位, 从最高位开始贪心
    {
        int k = val >> i & 1; // 得到 val 第i位的值
        if(trie[p][!k]) // 优选选择与val第i位相反的边权, 这样可以异或出1
        {
            sum  +=  1 << i;
            p = trie[p][!k];
        }
        else p = trie[p][k];
    }
    return sum;
}
int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
    {
        cin >> a[i];
        insert(a[i]);
    }
    for(int i=0; i<n; i++)
    {
        ans = max(ans, query(a[i]));
    }
    cout << ans << endl;
    return 0;
}
一道类似的题目

AcWing 1414. 牛异或: 需要用前缀和处理成上述模型

你可能感兴趣的:(Trie树,贪心)