zoukankan      html  css  js  c++  java
  • HDU 4760 Good FireWall 完好Trie题解

    本题乍看像是线段树之类的区间操作,只是由于仅仅是须要查找ip的前缀,故此事实上是使用Trie来做。

    挺高难度的Trie应用,做完这道题之后说明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 = searchNode(trie, ip, ipSrc);
    			ip = getIP();
    			if (src) src = searchNode(trie, ip, ipDes);
    			if (src)
    			{
    				sort(ipSrc.begin(), ipSrc.end());
    				sort(ipDes.begin(), ipDes.end());
    				bool hasSame = false;
    				for (int i = 0, j = 0; 
    					i < (int)ipSrc.size() && j < (int)ipDes.size(); )
    				{
    					if (ipSrc[i] == ipDes[j])
    					{
    						hasSame = true;
    						break;
    					}
    					else if (ipSrc[i] < ipDes[j]) i++;
    					else j++;
    				}
    				if (hasSame) puts("F");
    				else puts("D");
    			}
    			else puts("D");
    		}
    	}
    	return 0;
    }



  • 相关阅读:
    OD: Kernel Vulnerabilities
    newInstance()和new的区别
    原型模式
    工厂模式
    代理模式
    策略模式
    简单工厂模式
    C#操作符的重载
    旅行之舌尖上的中国
    模式和原则[转载]
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5181322.html
Copyright © 2011-2022 走看看