思路分析
这道题的题目一如既往的长,并且在其中给出了一些没有用的信息,比如说什么样的地址是不合法的,这些信息具有混淆性。
这道题有点类似于一道模拟题,跟着题目的意思做就好了,但是在程序设计方面可能需要一些构思。比如说IP前缀,有不止一种方法来存储。我在这里采用的方法是分部分存储。比如说1.0.0.0/16
这个就以/
为分界线,分为前后两大部份,前面那部分又以.
分为四部分进行存储,这样的存储方式有一个好处,就是简单,明了,计算爽,就很好玩。
代码部分
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
struct node {
vector<int> pre;//前部分
int suff;//后部分
bool operator < (const node& c) const {
int k = 0;
while (k < pre.size()) {
if (pre[k] != c.pre[k]) return pre[k] < c.pre[k];
++k;
}
return suff < c.suff;
}
};
//对ip前缀输入进行规范化
void mysplit(node& x, string now) {
vector<string> buff;
int k = 0;
while (k < now.size() && now[k] != '/') ++k;
if (k != now.size()) buff.insert(buff.begin(), now.substr(k + 1, now.size() - k - 1));
buff.insert(buff.begin(), now.substr(0, k));
vector<int> pre;
int tmp = 0;
for (int i = 0; i < buff[0].size(); ++i) {
if (buff[0][i] == '.') {
pre.push_back(tmp);
tmp = 0;
}
else tmp = tmp * 10 + buff[0][i] - 48;
}
pre.push_back(tmp);
k = 0;
while (k < 4) {
if (k >= pre.size()) x.pre.push_back(0);
else x.pre.push_back(pre[k]);
++k;
}
if (buff.size() == 1) x.suff = 8 * pre.size();
else if (buff.size() == 2) {
int tmp = 0;
for (int i = 0; i < buff[1].size(); ++i) tmp = tmp * 10 + buff[1][i] - 48;
x.suff = tmp;
}
return;
}
//判断ip前缀b是否为ip前缀a的子集
bool isequal(node& a, node& b) {
if (a.suff > b.suff) return false;
int bits = a.suff;
int k = bits / 8;
for (int i = 0; i < k; ++i) {
if (a.pre[i] != b.pre[i]) return false;
}
int extra = bits % 8;
if (extra == 0) return true;
else {
int r = 8 - extra;
int ae = a.pre[k] >> r;
int be = b.pre[k] >> r;
return ae == be;
}
}
//跟isequal函数差不多,只是多了一个前缀长度的比较
bool _isequal(node& a, node& b) {
if (a.suff != b.suff) return false;
--a.suff, --b.suff;//将前缀长度减1
return isequal(a, b);
}
//创造一个新的ip前缀
node crea(node a) {
int suff = a.suff;
int k = suff / 8, extra = 8 - suff % 8;
a.pre[k] >>= extra;
a.pre[k] <<= extra;
return a;
}
int main()
{
int k;
cin >> k;
vector<node> box;
while (k--) {
string now;
cin >> now;
node x;
mysplit(x, now);
box.push_back(x);
}
sort(box.begin(), box.end());
vector<node> clean;//存储子集合并的结果
clean.push_back(box[0]);
for (int i = 1; i < box.size(); ++i) {
if (!isequal(clean.back(), box[i])) clean.push_back(box[i]);
}
k = 1;
//下面进行位合并
while (clean.begin() + k != clean.end()) {
node ta = *(clean.begin() + k);
node tb = *(clean.begin() + k - 1);
if (_isequal(ta, tb)) {
node now = crea(ta);
--k;
clean.erase(clean.begin() + k);
clean.erase(clean.begin() + k);
clean.insert(clean.begin() + k, now);
if (k == 0) ++k;
}
else ++k;
}
//输出
for (int i = 0; i < clean.size(); ++i) {
for (int j = 0; j < clean[i].pre.size(); ++j) {
if (j != 0) cout << '.';
cout << clean[i].pre[j];
}
cout << '/';
cout << clean[i].suff << endl;
}
return 0;
}