题意
能够正确读取n个共3种(标准型,省略后缀型,省略长度型)ip地址列表
要你简化成等价的ip数目最小的前缀列表
解法很难,还好已经给了,只需跟着提示3步走
思路
采用下面的方式保存ip地址表
- 第二步中第三步要删除中间表项,使用list方便又效率高
- pair中定义了< 优先级为frist,second 我们直接把ip放在first 长度放在second就能符合题意
- unsinged int 占32位刚好为ip地址的长度,提取值就靠移位操作
list<pair<unsigned int, unsigned int>>iplist;
后面的按提示来就行
代码
#include <iostream>
#include <list>
#include <string>
#include <fstream>
#include <sstream>
#include <algorithm>
using namespace std;
list<pair<unsigned int, unsigned int>>iplist;
//#define DEBUG
void input() {
#ifdef DEBUG
fstream cin("input.txt");
#endif
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
cin.get();
while (n--)
{
unsigned int ip = 0, pre;
string temp;
getline(cin, temp);
stringstream strs;
strs << temp;
int point = count(temp.begin(), temp.end(), '.');
for (int i = 0; i < point + 1; ++i) {
ip <<= 8;
int tip;
strs >> tip;
strs.get();
ip += tip;
}
for (int i = 0; i < 3 - point; i++)ip <<= 8;
if (temp.find('/') != string::npos) {//省略后缀和标准
strs >> pre;
}
else {//省略长度
pre = (point + 1) * 8;
}
iplist.push_back({ ip, pre });
}
iplist.sort();//pair中已经定义了<小于优先级为先比较first再比较second
//处理好3种输入和排序已经60分了
}
void fun() {
for (auto i = iplist.begin(), j = ++iplist.begin(); j != iplist.end(); ) {//从小到大合并 80分
if (i->second <= j->second &&
i->first >> (32 - i->second) == j->first >> (32 - i->second))
{
j = iplist.erase(j);
}
else {
++i; ++j;
}
}
for (auto i = iplist.begin(), j = ++iplist.begin(); j != iplist.end();) {//同级合并100分
if (i->second != 0 &&//a次合法长度必须大于0才能减,其实后面想也没必要长度为0早就被上面合并为一个了进不来这
i->second == j->second &&
((i->first >> (32 - i->second)) ^ (j->first >> (32 - i->second))) == 1)//只有最后一位不同
{
--(i->second);
j = iplist.erase(j);
if (i != iplist.begin()) {//提示中要求往前跳
--i; --j;
}
}
else {
++i; ++j;
}
}
}
int main()
{
input();
fun();
for (auto x : iplist) {
for (int i = 0; i < 4; ++i, x.first <<= 8) {
cout << (x.first >> 24);
if (i != 3)cout << '.';
}
cout << '/' << x.second << endl;
}
}
自制测试数据
4
6
7.0.0.0/8
4.0.0/8
4.0/7
能测试提示中的3个步骤
答案4.0.0.0/6