2014百度之星资格赛解题报告:Xor Sum

Xor Sum
时间限制: 1S     空间限制:64M
问题描述
Zeus  和 Prometheus 做了一个游戏,Prometheus给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。你能证明人类的智慧么?
输入
输入包含若干组测试数据,每组测试数据包含若干行。
输入的第一行是一个整数 T T < 10 ),表示共有 T 组数据。
每组数据的第一行输入两个正整数 N M <1=N,M<=100000 ),接下来一行,包含 N 个正整数,代表  Zeus  的获得的集合,之后 M 行,每行一个正整数 S ,代表  Prometheus  询问的正整数。所有正整数均不超过 2^32
输出
对于每组数据,首先需要输出单独一行 ”Case #?:” ,其中问号处应填入当前的数据组数,组数从 1 开始计算。
对于每个询问,输出一个正整数 K ,使得 K S 异或值最大。
样例输入
2
3 2
3 4 5
1
5
4 1
4 6 5 6
3
样例输出
Case #1:
4
3
Case #2:
4

解题报告
由于每个正整数都不超过2 32 次方,所以将每个正整数的二进制数字作为字符串插入到字典树中,对于每一个询问,只需要按照贪心的做法搜索字典树就行了。
1.  将所有数字转为二进制。
2.  将集合中的所有二进制数变为一棵二叉树,左节点代表这一位为0 ,右节点代表1
3.  对每一个询问,在这课二叉树上查询,如果这一位为0 并且右孩子不为空,则往右走,否则往走左。最终到达叶子节点经过的路径就是所求的数的二进制表示。

解题代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#define LENGTH 32
#define MAXN 100000
using namespace std;
typedef struct node{
        node *next[2];
        bool flag;
};

node Head;
node arr[LENGTH * MAXN];
int nodeCount;

node *GetNewNode(){
        if (nodeCount >= LENGTH * MAXN) {
                printf("ERROR : node count full!");
                exit(1);
        }
        arr[nodeCount].next[0] = NULL;
        arr[nodeCount].next[1] = NULL;
        arr[nodeCount].flag    = false;
        return &(arr[nodeCount++]);
}

void Init(){
        nodeCount = 0;
        Head.next[0] = NULL;
        Head.next[1] = NULL;
        Head.flag    = false;
}

void insertNode(unsigned int num){
        node *p = &Head;
        int temp;
        for (int i = LENGTH - 1; i>=0; i--){
                if (((1<<i)&num) != 0){
                        temp = 1;
                } else {
                        temp = 0;
                }
                
                if (p->next[temp] == NULL){
                        p->next[temp] = GetNewNode();
                }
                
                p = p->next[temp];
        }
        p->flag = true;
}

unsigned int searchNode(unsigned int s){
        unsigned int k;
        node *p = &Head;
        int temp;
        k = 0;
        for (int i = LENGTH - 1; i>=0 ;i--){
                if (((1<<i)&s) != 0){
                        temp = 0;
                } else {
                        temp = 1;
                }
                
                if (p->next[temp] == NULL){
                        k = (k << 1) + (temp ^ 1);
                        p = p->next[temp ^ 1];
                } else {
                        k = (k << 1) + temp;
                        p = p->next[temp];
                }
        }
        return k;
}

int main(){
        int n , m ;
        unsigned int k , s;
        Init();
        int case_count = 0;
        scanf("%d", &case_count);
        int case_index = 0;
        while ((case_count--) && scanf("%d%d" , &n , &m) != EOF){
                case_index++;
                printf("Case #%d:\n", case_index);
                Init();
                for (int i = 0; i < n; i++){
                        scanf("%u",&k);
                        insertNode(k);
                }
                for (int i = 0; i < m; i++){
                        scanf("%u" , &s);
                        k = searchNode(s);
                        printf("%u\n" , k);
                }
        }
        return 0;
}


转载于:https://www.cnblogs.com/hosealeo/p/4190533.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值