由于题目繁琐,本篇文章只解决题目中最简单的处理情况,可以得60分
试题编号: | 201812-3 |
试题名称: | CIDR合并 |
时间限制: | 1.0s |
内存限制: | 512.0MB |
问题描述: | 样例输入 2 样例输出 1.0.0.0/8 样例输入 2 样例输出 10.0.0.0/8 样例输入 2 样例输出 0.0.0.0/0 |
问题链接:CCF201812-3 CIDR合并
问题分析
这个题目实在是太长了。我花了大半天去读题也没有理解题目中的一些概念(ip前缀的匹配)所以做题时无从下手。
好在这道题最后说明了测试点的几种情况,所以我觉得觉得这道题目有困难的同学,可以用最少的时间拿分(把最简单的测试点通过),意思就是我们只处理第一个测试点(只需要完成排序操作)。下面分析怎么处理第一个测试点的情况:
首先,我们先明确要想通过测试点1需要怎样操作,大致可以分为以下几点:1.将输入格式化,题目中给出的输入可能缺少ip,也可能缺少前缀,也可能全部缺少,所以首先将输入格式化成标准形式。2.根据ip的大小进行排序。3.将ip值相同的元素根据前缀大小进行排序。4.输出结果。
我在下面代码中将这四个步骤分为两个函数去编写(ip_to_d是将ip地址转化为10进制以完成第一个排序),具体实现请阅读下面不是满分的代码。
60分代码
#将输入的数据预处理,变为合法的ip前缀表达式
def change_in(s):
#找到‘/’位置和有几个‘.'
position=0
point=0
for i in range(len(s)):
if s[i]=='/':
position=i
if s[i]=='.':
point+=1
if position==0:
position=len(s)
s+=('/'+str(8+point*8))
point=3-point
#构造新的ip地址
re=[]
re+=[s[0:position]]
for i in range(point):
re[0]+=".0"
#将ip地址和前缀大小分开,方便后面计算([1.1.1.1,/5])的形式
re+=[int(s[position+1:])]
return re
#将ip地址变为十进制数
def ip_to_d(s):
num=[]
befor=''
for i in range(len(s[0])):
if s[0][i]=='.':
num+=[int(befor)]
befor=''
else:
befor+=s[0][i]
num+=[int(befor)]
re_num=0
for i in range(4):
re_num+=(num[i]*(256**(3-i)))
return re_num
#对s里面的ip地址进行排序
def ip_sort(s):
t=[]
for i in range(len(s)):
t+=[[ip_to_d(s[i]),i]]
#首先对ip地址的大小进行排序
t.sort(key=lambda x:x[0])
re=[]
for i in range(len(s)):
re+=[s[t[i][1]]]
#其次对相同大小的ip地址进行前缀排序
#将ip地址相同的元素依据前缀大小进行排序(为简单起见,用冒泡)
for i in range(len(re)-1):
for j in range(i+1,len(re)):
if re[i][0]==re[j][0] :
if re[i][1]>re[j][1]:
re[i],re[j]=re[j],re[i]
return re
#程序执行
n=int(input())
s=[]
for i in range(n):
s+=[input()]
for i in range(n):
s[i]=change_in(s[i])
s=ip_sort(s)
for i in range(len(s)):
print(s[i][0]+'/'+str(s[i][1]))