本题乍看像是线段树之类的区间操作,不过因为只是需要查找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 = 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; }
HDU 4760 Good FireWall 完善Trie题解
时间: 2024-10-06 20:38:23