題目想求與給定前綴列表等價的包含IP前綴數目最少的前綴列表。c++
首先是怎麼存儲前綴列表。用一個long long存儲IP地址,再存一個前綴長度,封裝在一個結構體裏\(<ipNum, len>\),方便後面排序等操做。IP前綴有三種輸入格式,稍微分狀況討論一下。spa
接着以\(ipNum\)爲第一關鍵字,\(len\)爲第二關鍵字升序排序。code
而後考慮去除匹配集被其它IP前綴包含的IP前綴。考慮以前匹配集範圍的上屆\(mmax\),順序遍歷一下就行了。將剩餘的IP列表按以前順序存在一個靜態鏈表中。排序
最後將相鄰的可合併的IP前綴合並,其實就是前綴長度最後一位0和1,以前徹底相同便可。ip
溫習一下鏈表的插入刪除操做。get
#include <bits/stdc++.h> typedef long long LL; const int maxn = 1000000; using namespace std; struct tIP { LL ipNum; int len; int before, next; tIP() { before = next = -1; } bool operator < (const tIP &y) const { if(ipNum == y.ipNum) return len < y.len; return ipNum < y.ipNum; } void show() { LL num[5]; LL temp = ipNum; for (int i = 4; i >= 1; i--) { num[i] = temp % 256; temp /= 256; } for (int i = 1; i <=4; i++) { printf("%lld", num[i]); if (i == 4) printf("/"); else printf("."); } printf("%d\n", len); } }; tIP ip[maxn+10]; LL getMMax(tIP iip) { LL temp = (1LL << (32-iip.len)) - 1; return iip.ipNum | temp; } int main() { int n; scanf("%d", &n); char s[30]; for (int id = 1, slash, dotCnt, style; id <= n; id++) { slash = 0; dotCnt = 0; scanf("%s", s + 1); for (int i = 1; s[i] != '\0'; i++) { if (s[i] == '/') slash = 1; if (s[i] == '.') dotCnt ++; } if (slash == 1 && dotCnt == 3) style = 1; else if (slash == 1 && dotCnt < 3) style = 2; else style = 3; LL num[5]; memset(num, 0, sizeof(num)); if (style == 1 || style == 2) { for (int i = 1, temp = 0, numCnt = 1; ; i++) { if (s[i] == '.' || s[i] == '/') { num[numCnt++] = temp * 1LL; temp = 0; } else if (s[i] == '\0') { ip[id].len = temp; break; } else { temp = temp * 10 + s[i] - '0'; } } } else { for (int i = 1, temp = 0, numCnt = 1; ; i++) { if (s[i] == '.') { num[numCnt++] = temp * 1LL; temp = 0; } else if (s[i] == '\0') { num[numCnt++] = temp * 1LL; ip[id].len = (numCnt-1) * 8; break; } else { temp = temp * 10 + s[i] - '0'; } } } LL ans = 0; for (int i = 1; i <= 4; i++) { ans = ans * 256 + num[i]; } ip[id].ipNum = ans; } sort(ip + 1, ip + 1 + n); LL mmax = -1; int st = 0, en = n + 1; ip[st].before = -1; ip[st].next = en; ip[en].before = st; ip[en].next = -1; for (int id = 1, prev = 0; id <= n; id++) { if (ip[id].ipNum > mmax) { ip[id].before = prev; ip[id].next = en; ip[prev].next = ip[en].before = id; prev = id; mmax = getMMax(ip[id]); } } int pNow = ip[0].next; while (pNow != en) { int p1 = pNow, p2 = ip[pNow].before; if (p2 == 0) pNow = ip[pNow].next; else { if (ip[p1].len == ip[p2].len && (ip[p2].ipNum & (1LL << (32-ip[p2].len))) == 0 && (ip[p2].ipNum | (1LL << (32-ip[p2].len))) == ip[p1].ipNum) { ip[p1].before = ip[p2].before; ip[ip[p1].before].next = p1; ip[p1].ipNum = ip[p2].ipNum; ip[p1].len --; } else { pNow = ip[pNow].next; } } } pNow = ip[0].next; while (pNow != en) { ip[pNow].show(); pNow = ip[pNow].next; } return 0; }