CCF 2018-12-3 CIDR合并 100分

在这里插入图片描述

题意

能够正确读取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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值