1. 程式人生 > >HDU 4825 (字典樹 +貪心)

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;
}