CSP201812-3 CIDR合并
题目
解题思路
按照题目给出的提示进行解答
考虑合并时,将IP地址转换为长整型的数据判断范围
如果使用vector会超时,因为第三部合并时涉及到大量的删除和插入操作,所以使用list。
代码
#include <bits/stdc++.h>
using namespace std;
/*列表中包含的IP地址可能存在交集*/
pair<long long int, long long int> ans;
struct node {
int a[4];
int len;
node(int n[4], int len) :len(len) {
for (int i = 0; i < 4; i++)
a[i] = n[i];
}
};
bool cmp(const node& m, const node& n) {
if (m.a[0] == n.a[0]) {
if (m.a[1] == n.a[1]) {
if (m.a[2] == n.a[2]) {
if (m.a[3] == n.a[3]) {
return m.len < n.len;
}
return m.a[3] < n.a[3];
}
return m.a[2] < n.a[2];
}
return m.a[1] < n.a[1];
}
return m.a[0] < n.a[0];
}
list<node> Node;
int n;
void getNode(string s) {
//处理输入
int pre_pos = -1;
int i = -1;
int a[4];
int len;
int pos = s.find('.');
int pos_ = s.find('/');
while (pos != string::npos) {
a[++i] = stoi(s.substr(pre_pos + 1, pos - pre_pos - 1));
pre_pos = pos;
pos = s.find('.', pos + 1);
}
if (pos_ != string::npos) {
a[++i] = stoi(s.substr(pre_pos + 1, pos_ - pre_pos - 1));
len = stoi(s.substr(pos_ + 1));
}
else {
a[++i] = stoi(s.substr(pre_pos + 1));
len = (i + 1) * 8;
}
while (i < 3)
a[++i] = 0;
Node.push_back({ a, len });
}
pair<long long int, long long int> getInt(node n, int len) {
/*计算IP地址对应的十六进制整数判断匹配集范围*/
long long int ans_min = 0;
long long int tmp = 1;
long long int ans_max = 0;
for (int i = 0; i < 4; i++) {
ans_min += ((long long int)n.a[3 - i] << (8 * i));
}
ans_max = ans_min;
int i = (len + 7) / 8;//上取整
long long int offset = 0xff >> (len - (i - 1) * 8);
tmp = 1;
int j;
for (j = 0; j < 4 - i; j++) {
ans_max += ((long long int)255 << (8 * j));
}
ans_max += (offset << (8 * j));
return { ans_min,ans_max };
}
bool JudgeLegal(node& n) {/*判断是否合法*/
int len = n.len - 1;
int i = (n.len + 7) / 8;
int offset = 1 << (i * 8 - len - 1);
if ((n.a[i - 1] & offset) == 0)//只需要判断前移的那一位是否为0
return true;
return false;
}
int main() {
ios::sync_with_stdio(false);
cin >> n;
for (int i = 0; i < n; i++) {
string str;
cin >> str;
getNode(str);
}
Node.sort(cmp);
/*从小到大合并*/
list<node>::iterator i;
list<node>::iterator j = Node.begin();
for (i = Node.begin(); i != Node.end(); i++) {
j++;
pair<long long int, long long int> ans_i = getInt(*i, (*i).len);
while (j != Node.end()) {
pair<long long int, long long int> ans_j = getInt(*j, (*j).len);
if (ans_i.first <= ans_j.first && ans_i.second >= ans_j.second) {
j = Node.erase(j);
continue;
}
break;
}
}
/*同级合并*/
i = Node.begin();
j = Node.begin();
while (i != Node.end()) {
j++;
if ((*i).len != (*j).len) {
i++;
continue;
}
if (JudgeLegal(*i)) {
pair<long long int, long long int> ans_i = getInt(*i, (*i).len);
pair<long long int, long long int> ans_tmp = getInt(*i, (*i).len - 1);
if (j != Node.end()) {
pair<long long int, long long int> ans_j = getInt(*j, (*j).len);
long long int left = min(ans_i.first, ans_j.first);
long long int right = max(ans_i.second, ans_j.second);
node tmp((*i).a, (*i).len - 1);
if (left == ans_tmp.first && right == ans_tmp.second) {//如果并集和a'相等
i = Node.erase(i);//移除i
i = Node.erase(i);//移除j
if (Node.empty() || i == Node.begin()) {
Node.push_front(tmp);
i = Node.begin();
j = i;
}
else {
Node.insert(i, tmp);
--i;
--i;
j = i;
}
continue;//否则,i为0,从a'开始
}
else {//如果并集不相等
i++;//考虑下一组相邻
continue;
}
}
else
break;
}
else
i++;
}
for (list<node>::iterator it = Node.begin(); it != Node.end(); it++) {
cout << (*it).a[0];
for (int j = 1; j < 4; j++)
cout << "." << (*it).a[j];
cout << "/" << (*it).len << endl;
}
}