首页 > 代码库 > HDU 4760 Good FireWall 完善Trie题解

HDU 4760 Good FireWall 完善Trie题解

本题乍看像是线段树之类的区间操作,不过因为只是需要查找ip的前缀,故此其实是使用Trie来做。

这里的Trie使用到了Delete函数,这是个Trie函数中最难的函数了,当然要使用数组记录的方法水掉,也是可以的。这里不水,给出delete函数。

考点难点:

1 Trie的操作函数的灵活运用,主要难点是delete函数的灵活运用

2  在叶子节点所有的group id, 删除的时候要注意,不能一气删除了,有多个group id会挂在同一颗树中

3  源ip和目的ip也许在多个叶子节点中,要使用两个vector记录所有group id,然后使用查找两集合是否有公共值的算法解之

4 ip值转换为一个整数值记录就可以了,这里使用了unsigned,不过应该是int也可以的,因为只需要操作其二进制值,和整数值无关。

5 使用mask值,mask值后面的0可以不管,加速程序

所有问题考虑全,高级数据结构中包括各种小问题处理,大算法中使用到多种小算法,综合难度超过5星级。做完后很有成就感O(∩_∩)O哈哈~。

#include <stdio.h>
#include <bitset>
#include <vector>
#include <algorithm>
using namespace std;

const int MAX_ID = 1024;
const int MAX_LINE = 32769;
const int MAX_N = 15;
const int ARR_SIZE = 2;
const int MAX_DIGIT = 32;
const int MAX_NODE = MAX_ID*MAX_DIGIT*MAX_N;
unsigned gEnableIdIpMask[MAX_ID][MAX_N<<1];
int gLen[MAX_ID], id;

struct Node
{
	int n;
	vector<int> id;
	Node *arr[ARR_SIZE];
};

void clearNode(Node *rt)
{
	rt->n = 0;
	rt->id.clear();
	for (int i = 0; i < ARR_SIZE; i++)
	{
		rt->arr[i] = NULL;
	}
}

Node pool[MAX_NODE];
int poolID;

void insertTrie(Node *trie, unsigned dig, unsigned mark, int id)
{
	bitset<MAX_DIGIT> bi = dig;
	int m = MAX_DIGIT - mark;
	for (int i = MAX_DIGIT-1; i >= m; i--)
	{
		Node *&p = trie->arr[bi[i]];//注意*&p,操作同名地址变量
		if (!p)//判断成if(p),程序崩溃。
		{
			p = &pool[poolID++];
			clearNode(p);
		}
		trie = p;
	}
	trie->n++;
	trie->id.push_back(id);
}

bool searchNode(Node *trie, unsigned dig, vector<int> &id)
{
	bitset<MAX_DIGIT> bi = dig;
	bool flag = false;
	for (int i = MAX_DIGIT-1; i >= 0; i--)
	{
		trie = trie->arr[bi[i]];
		if (!trie) return flag;
		if (trie->n)
		{
			flag = true;
			id.insert(id.end(), trie->id.begin(), trie->id.end());
		}
	}
	return flag;
}

inline bool isFreeNode(Node *rt)
{
	for (int i = 0; i < ARR_SIZE; i++)
	{
		if (rt->arr[i]) return false;
	}
	return true;
}

bool deleteNodeHelper(Node *trie, bitset<MAX_DIGIT> &bi, int mask, int id,
				  int lv = MAX_DIGIT-1)//注意lv含义,准确赋值
{
	if (trie)
	{
		if (mask-1 == lv)//注意:下标计算,对齐
		{			
			if (trie->n)
			{
				if (trie->n > 1)
				{
					int j = 0;
					for (; j < trie->n; j++) if (trie->id[j] == id) break;
					trie->id.erase(trie->id.begin()+j);
					trie->n--;
				}
				else
				{
					trie->n = 0;
					trie->id.clear();
					return isFreeNode(trie);
				}				
			}
		}
		else
		{
			if (deleteNodeHelper(trie->arr[bi[lv]], bi, mask, id, lv-1))
			{
				trie->arr[bi[lv]] = NULL;
				return !trie->n && isFreeNode(trie);
			}
		}
	}
	return false;
}

inline void deleteNode(Node *trie, unsigned dig, unsigned mask, int id)
{
	bitset<MAX_DIGIT> bi = dig;
	int m = MAX_DIGIT - mask;	//注意长度计算
	deleteNodeHelper(trie, bi, m, id);
}

unsigned getIP()
{
	unsigned ip = 0;
	unsigned part;
	for (int j = 3; j >= 0; j--)
	{
		scanf("%u", &part);
		getchar();
		ip |= part<<(j<<3);
	}
	return ip;
}

int main()
{
	char cmd;
	unsigned ip, mask;
	Node *trie = &pool[0];
	clearNode(trie);
	poolID = 1;
	while (scanf("%c", &cmd) != EOF)
	{
		if (cmd == 'E')
		{
			scanf("%d", &id);
			scanf("%d", gLen+id);
			for (int i = 0; i < gLen[id]; i++)
			{
				ip = getIP();				
				scanf("%u", &mask);
				gEnableIdIpMask[id][i<<1] = ip;
				gEnableIdIpMask[id][i<<1|1] = mask;
				insertTrie(trie, ip, mask, id);
			}
			getchar();
		}
		else if (cmd == 'D')
		{
			scanf("%d", &id);
			getchar();
			for (int i = 0; i < gLen[id]; i++)
			{
				deleteNode(trie, gEnableIdIpMask[id][i<<1], 
					gEnableIdIpMask[id][i<<1|1], id);
			}
			gLen[id] = 0;
		}
		else// if (cmd == 'F')
		{
			ip = getIP();
			vector<int> ipSrc, ipDes;
			bool src = http://www.mamicode.com/searchNode(trie, ip, ipSrc);>