HDU 4825 (字典树 +贪心)

Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包含了N个正整数,随后 Prometheus 将向 Zeus 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。Prometheus 为了让 Zeus 看到人类的伟大,随即同意 Zeus 可以向人类求助。你能证明人类的智慧么? 

Input

输入包含若干组测试数据,每组测试数据包含若干行。 
输入的第一行是一个整数T(T < 10),表示共有T组数据。 
每组数据的第一行输入两个正整数N,M(<1=N,M<=100000),接下来一行,包含N个正整数,代表 Zeus 的获得的集合,之后M行,每行一个正整数S,代表 Prometheus 询问的正整数。所有正整数均不超过2^32。

Output

对于每组数据,首先需要输出单独一行”Case #?:”,其中问号处应填入当前的数据组数,组数从1开始计算。 
对于每个询问,输出一个正整数K,使得K与S异或值最大。

Sample Input

2
3 2
3 4 5
1
5
4 1
4 6 5 6
3

Sample Output

Case #1:
4
3
Case #2:

解题思路:

将输入的N个数转化为2禁止,补全前导0,由于所有整数都不超过2^32位,所以补为32位,然后存入字典树中。

对于每个每次查询,同样将S化为二进制,补全前导0,要想使得到的结果最大,可以利用贪心的思想,取S二进制的反。然后从字典中查找,如果该位存在,沿着这一位往下找(确保最大),如果不存在,走不相等的那个。

代码如下:

1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#define maxn 100005
using namespace std;
int vis[maxn];   // 记录Zeus的集合
int k=0;
typedef struct Trie
{
    Trie *next[2];
    int sum;  
};
Trie *root;
void init()
{
    root=new Trie;
    for(int i=0; i<2; i++)
    {
        root->next[i]=NULL;
    }
}
void createTrie(int num)   // 建立字典树
{
    char str[35];
    for(int i=31; i>=0; i--)
    {
        int temp=((num>>i)&1);
        char c=temp+'0';
        //cout<<c<<endl;
        str[i]=c;
    }
    Trie *p=root;
    for(int i=31; i>=0; i--)
    {
        int id=(int)(str[i]-'0');
        if(p->next[id]==NULL)
        {
            p->next[id]=new Trie;
            p=p->next[id];
            p->sum=0;
            for(int j=0; j<2; j++)
            {
                p->next[j]=NULL;
            }
        }
        else
        {
            p=p->next[id];
        }
        //cout<<"111"<<endl;
    }
    p->sum=k++;
}
int fin(char str[])
{
    int len=strlen(str);
    Trie *p=root;
    for(int i=31; i >=0; i--)
    {
        int id=(int)(str[i]-'0');
        if(p->next[id]!=NULL)p=p->next[id]; // 如果该进点不为空,进入该节点。
        else if(p->next[1-id]!=NULL)     // 否则进入另一个
        {
            p=p->next[1-id];
        }
    }
    return p->sum;
}
int main()
{

    int t;
    scanf("%d",&t);
    int n,m;
    int d;
    int cas=1;
    char ch[35];
    int v[maxn];
    while(t--)
    {    k=0;
         init();
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++)
        {
            scanf("%d",&vis[i]);
            createTrie(vis[i]);
        }
        printf("Case #%d:\n",cas++);
        for(int i=1; i<=m; i++)
        {
            memset(ch,'\0',sizeof(ch));
            scanf("%d",&d);
            for(int j=31; j>=0; j--)
            {
                int temp=((d>>j)&1);
                if(temp==1)temp=0;
                else if(temp==0)temp=1;
                char d=temp+'0';
                ch[j]=d;
            }
            printf("%d\n",vis[fin(ch)]);
            //cout<<vis[fin(ch)]<<endl;
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/YANSHUOXU/article/details/84037655