题意:
输入IPv4地址空间中的一些子网号,构成一个网络集合。
输出个数最小的一个网络集合,要求其与输入集合没有交集,且相对与IPv4地址空间全集,与输入集合互为补集。
输出集合包含的子网号,格式遵循网络规范。
解析:
这题可以用Trie树来搞。
每个IP地址由32位二进制组成。整个地址空间可以表现为一棵二叉树。
用Trie的节点标记每个二进制串所能抵达的终点,即子网覆盖的终点位置。
建立Trie树后,DFS遍历树上的分支,输出没有被覆盖的分支即可。
my
code
#include
#include
#include
#include
#include
#define pb push_back using namespace std; typedef long long ll; const int maxnode = (int)5e5 + 10; const int sigma_size = 2; vector
ans; struct Trie { int ch[maxnode][2]; bool val[maxnode]; int sz; void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } Trie() { clear(); } int idx(char c) { return c - '0'; } void insert(char* s, int len) { int u = 0; for(int i = 0; i < len; i++) { int c = idx(s[i]); if(!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = false; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = true; } void setIp(ll ip, int len) { int a[4]; char buf[30]; for(int i = 3; i >= 0; i--) { a[i] = ip % 256; ip >>= 8; } sprintf(buf, %d.%d.%d.%d/%d, a[0], a[1], a[2], a[3], len+1); ans.pb(buf); } void dfs(int u, int dep, ll cur) { if(val[u]) return; for(int i = 1; i >= 0; i--) { ll ip = cur | ((ll)i << (31-dep)); if(!ch[u][i]) setIp(ip, dep); else dfs(ch[u][i], dep+1, ip); } } } trie; int n; char bit[33]; void trans(char* s, ll ip) { for(int i = 31; i >= 0; i--) s[31-i] = ((ip >> i) & 1) + '0'; s[32] = ''; } ll getIp(ll a, ll b, ll c, ll d) { return (1LL << 24) * a + (1LL<<16) * b + (1LL<<8) * c + d; } int main() { int T, cas = 1; scanf(%d, &T); while(T--) { trie.clear(); ans.clear(); scanf(%d, &n); printf(Case #%d: , cas++); if(n == 0) { puts(1 0.0.0.0/0); continue; } ll a, b, c, d, len, ip; for(int i = 0; i < n; i++) { scanf(%lld.%lld.%lld.%lld/%lld, &a, &b, &c, &d, &len); ip = getIp(a, b, c, d); trans(bit, ip); trie.insert(bit, len); } trie.dfs(0, 0, 0); int size = ans.size(); printf(%d , size); for(int i = 0; i < size; i++) { printf(%s , ans[i].c_str()); } } return 0; }
?