hdu4825

Problem Description

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:
4
解题思路:将给定得数按照二进制建成一颗字典树,每一层分别对应的各个位数上的01状态, 然后每一次查询,如果对应位置为0,则要往1的方向走,如果是1,则要往0的方向走。但是要注意,走的前提是对应分支是存在的。

说明:自己写的,很低级。。。

#include "stdafx.h"
#include "iostream"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
using namespace std;

#define MAX 2 //用二进制,每个节点最多有两个分支
#define maxlen pow(2,8)-1 //二进制码的长度

int *dec2Bin(int dec);//十进制转二进制
int bin2Dec(int* bin);//二进制转十进制
//定义字典树结构
struct Trie
{
	Trie *next[MAX];
	int v;   //是否到达结尾的标志
};
Trie* createTrie(Trie *root, int *arr);//创建树
int* findTrie(Trie *root, int *arr);//查找树
int dealTrie(Trie* T);//删除树

int main()
{   
	int T;//数据组数  
	cin >> T;

	int *N = new int[T];//Zeus获得数数
	int *M = new int[T];//要询问的数
	int** re = new int*[T];//搜索到的结果

	for (int i = 0; i < T; i++)
	{   
		Trie *tree = new Trie;
		Trie *root = new Trie;

		for (int m = 0;m < MAX; ++m)
		{
			root->next[m] = NULL;
		}
		cin >> N[i] >> M[i];
		int *set=new int[N[i]]();
		re[i] = new int[M[i]];

		for (int j = 0; j < N[i]; j++)
		{
			cin >> set[j];
			int *setBin = dec2Bin(set[j]);
			tree = createTrie(root, setBin);
		}

		for (int k = 0; k < M[i]; k++)
		{   
			int obj;
			cin >> obj;
			int *binObj = dec2Bin(obj);
			int* tmp = findTrie(tree, binObj);
			re[i][k] = bin2Dec(tmp);
		}
		dealTrie(tree);
	}
	for (int i = 0; i < T; i++)
	{
		cout << "Case #" << i + 1 << ":" << endl;
		for (int j = 0; j < M[i]; j++)
		{
			cout << re[i][j] << endl;
		}
	}
	system("pause");
	return 0;
}

Trie* createTrie(Trie *root, int *arr)
{
	int len = maxlen;
	Trie *p = root; Trie *q = new Trie;
	for (int i = 0; i<len; i++)
	{
		int id = arr[i];
		if (p->next[id] == NULL)
		{
			q = (Trie *)malloc(sizeof(Trie));
			q->v = 1;
			for (int j = 0; j<MAX; j++)
				q->next[j] = NULL;
			p->next[id] = q;
			p = p->next[id];
		}
		else
		{
			//p->next[id]->v++;
			p = p->next[id];
		}
	}
	p->v = -1;   //若为结尾,则将v改成-1表示
	return root;
}

int* findTrie(Trie *root, int *arr)
{
	Trie *p = root;
	int len = maxlen;
	int* re = new int[len]();
	for (int i = 0; i < len; i++)
	{
		int id = arr[i];
		if (p->next[1 - id] != NULL)//优先选择与要查询的数这一位相反的方向
		{
			re[i] = 1 - id;
			p = p->next[1 - id];
		}
		else
		{
			p = p->next[id];
			re[i] = id;
		}
	}
	return re;
}

int dealTrie(Trie* T)
{
	int i;
	if (T == NULL)
		return 0;
	for (i = 0; i < MAX; i++)
	{
		if (T->next[i] != NULL)
			dealTrie(T->next[i]);
	}
	free(T);
	return 0;
}

int* dec2Bin(int dec)
{
	int len = maxlen;
	int *b = new int[len]();;
	int i = dec;
	int j = 1;
	while (i)
	{
		b[len-j] = i % 2;
		i = i / 2;
		j++;
	}
	return b;
}

int bin2Dec(int* bin)
{   
	int len = maxlen;
	int re=0;
	for (int i = 0; i < len; i++)
	{
		re += pow(2, len - 1 - i)*bin[i];
	}
	return re;
}

    另外把给出的答案记录一下:

觉得大神写的太巧妙了,,,

#include "stdafx.h"
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
//typedef __int64 ll;
typedef long long ll;

const int M = 55;
const int N = M*1e5;

struct Node {
	ll val;
	int l;
	int r;

	void clear() {
		l = r = -1;
	}
}node[N];

int p;
ll a, t[M];

void insert(int& root, int d, ll u) {//尤其注意这里的按引用调用!!!root值改变的话,node[root].l的值也改变了!!!!,并且递归到底后root=51后,要逐层返回,最后root为0

	if (root == -1) {
		root = p++;
		node[root].clear();
	}

	if (d == -1) {
		node[root].val = u;
		return;
	}

	if (u & t[d])
		insert(node[root].r, d - 1, u);
	else
		insert(node[root].l, d - 1, u);
}

void query(int root, int d, ll u) {

	if (d == -1) {
		printf("%lld\n", node[root].val);
		return;
	}

	if (((u & t[d]) && node[root].l != -1) || node[root].r == -1)
		query(node[root].l, d - 1, u);
	else
		query(node[root].r, d - 1, u);
}

int main() {
	//cout << sizeof(unsigned int);
	int cas, n, m;
	scanf("%d", &cas);

	t[0] = 1;
	for (int i = 1; i < 55; i++)
		t[i] = t[i - 1] * 2;

	for (int i = 1; i <= cas; i++) {
		p = 0;
		int root = -1;

		scanf("%d%d", &n, &m);
		for (int j = 0; j < n; j++) {
			scanf("%lld", &a);
			insert(root, 50, a);
		}

		printf("Case #%d:\n", i);
		for (int j = 0; j < m; j++) {
			scanf("%lld", &a);
			query(root, 50, a);
		}
	}
	return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值