CIDR合并(CCF2018-12 3)

这个代码测试只能拿40分,大家看看就好,等我有时间了再改改…
一、题目
在这里插入图片描述二、分析
整个题目可以分成以下几部分:输入、排序、从小到大合并、同级合并、输出
1.输入
输入可能有三种形式,但要统一成一种形式,为了方便后面的排序,我建了一IP类,包含32位二进制IP地址字符串和它的前缀长度。用ArrayList存储IP对象。
遍历输入的ip字符串,记录遇到小数点的次数和是否遇到斜杠,从而可以判断输入的ip地址的类型。与此同时,在遍历ip字符串同时,记录数字字符并转换为二进制字符串,每当遇到小数点或者斜杠时更新该字符串。(这样做需要单独考虑输入为纯数字的情况)
最后,如果输的ip是标准型,则直接存储二进制字符串;若是省略后缀型,则补全二进制字符串后面缺的0;若是省略长度型,后缀长度即为(小数点个数+1)*8.

2.排序
实现Comparator借口,重写compare函数对List排序。

3.从小到大合并
遍历存储IP对象的链表,比较当前IP和下一个IP(a,b)。若a的后缀长度大于b的后缀长度,b的匹配集一定不是a的匹配集的子集,直接比较下一项。否则,遍历a,b的二进制字符串,若前a.len位都相同,则b的匹配集是a的匹配集的子集,删除b,同时指针前移。

4.同级合并
仍是遍历存储IP对象的链表,比较当前IP和下一个IP(a,b),对a的前缀长度减一,得到aa,若aa是合法的并且a和b的前缀长度相同,开始判断a,b匹配集的并集是否和aa的匹配集相同:遍历a,b的前len-1位,若每一位都相同,则表示可以用aa替代a和b。替代可以用set函数,用aa替代a,同时删除b。然后判断aa是否是链表的第一个元素,若不是则需要前移指针。

5.输出
遍历链表中每一个IP对象。每八位二进制转换为1个十进制数,加上小数点,最后的斜杠后后缀输出即可。

三、代码

package cidr合并;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;

class IP {
	String ip; // 32位二进制
	int len; // 前缀长度

	public IP(String ip, int len) {
		this.ip = ip;
		this.len = len;
	}
}
class IPComparator implements Comparator<IP> {
	@Override
	public int compare(IP o1, IP o2) {
		long a =Long.parseLong(o1.ip,2)-Long.parseLong(o2.ip,2);
		if(a==0)
			return o1.len-o2.len>0?1:-1;
		else
			return a>0?1:-1;
	}  //按照IP和前缀长度升序排序
}
public class Main {
	static int n;
	static List<IP> ipSet;
	
	private static void storeInput(String ip)  //存储输入
	{
		int pnum = 0;             //'.'出现的次数
		boolean flag = false;     //'/'出现为true
		int len;                  //IP前缀
		String number = "";       //记录8位2进制
		String bin = "";          // 32位二进制IP地址
		for (int i = 0; i < ip.length(); i++)
		{
			char pos = ip.charAt(i);
			if (pos >= '0' && pos <= '9')
				number += ip.charAt(i);
			else if (ip.charAt(i) == '.') {
				bin += String.format("%08d", Integer.parseInt(Integer.toBinaryString(Integer.parseInt(number))));
				//用format函数对不足8位的二进制字符串前面补0
				number = "";
				pnum++;
				continue;
			} else {
				bin += String.format("%08d", Integer.parseInt(Integer.toBinaryString(Integer.parseInt(number))));
				number = "";
				flag=true;
				break;
			}
		}
		if(pnum!=3)  //省略后缀型
		{
			if(pnum==0&&flag==false)  //若输入的ip是一个纯数字,上面的循环处理不到
				bin=String.format("%08d",  Integer.parseInt(Integer.toBinaryString(Integer.parseInt(ip))));
			int lack = 32-bin.length();   
			for(int i=0;i<lack;i++)  //补齐后面的0
				bin+="0";
		}
		if(!flag)  //省略长度型
			len=(pnum+1)*8;
		else 
			len = Integer.parseInt(ip.substring(ip.indexOf('/') + 1)); // 获取ip前缀
		ipSet.add(new IP(bin,len));   
	}
	private static void ascCombine()   //从小到大合并
	{
		for(int i=0;i<ipSet.size()-1;i++)
		{
			boolean flag = true;
			IP a = ipSet.get(i);
			IP b = ipSet.get(i+1);
			if(a.len>b.len)   //b的匹配集一定不是是a的子集
				continue;
			else
			{
				for(int j=0;j<a.len;j++)
				{
					if(a.ip.charAt(j)!=b.ip.charAt(j))
					{
						flag=false;
						break;
					}
				}
			}
			if(flag)       //b的匹配集是a的子集,删除b
			{
				ipSet.remove(i+1);
				i--;
			}
		}
	}
	private static void sameCombine()  //同级合并
	{
		LOOP1:for(int i=0;i<ipSet.size()-1;i++)
		{
			IP a = ipSet.get(i);
			IP b = ipSet.get(i+1);
			IP aa = new IP(a.ip,a.len-1);
			if(a.ip.length()==b.ip.length()&&checkIP(aa))
			{
					for(int j=0;j<aa.len;j++)
					{
						if(a.ip.charAt(j)!=b.ip.charAt(j))
							continue LOOP1;
					}
					ipSet.set(i, aa);  //用aa替换a,并删除b
					ipSet.remove(i+1); 
					if(i!=0) i--;  
			}
		}
	}
	private static boolean checkIP(IP t)  //检查IP前缀是否合法
	{
		for(int i=t.len;i<t.ip.length();i++)
			if(t.ip.charAt(i)!='0')
				return false;
		return true;
	}
	private static void print()
	{
		for(int i=0;i<ipSet.size();i++)
		{
			String ip = ipSet.get(i).ip;
			String d_ip="";
			String s ="";
			for(int j=0;j<ip.length();j++)
			{
				s+=ip.charAt(j);
				if(j%8==7&&j!=31)
				{
					d_ip+=Integer.parseInt(s, 2);
					d_ip+='.';
					s="";
				}	
			}
			d_ip+=Integer.parseInt(s,2);
			d_ip+='/';
			d_ip+=ipSet.get(i).len;
			System.out.println(d_ip);
		}
	}
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		n = in.nextInt();
		ipSet = new ArrayList<IP>();
		for (int i = 0; i < n; i++) {
			String ip = in.next();
			storeInput(ip);
		}
		Collections.sort(ipSet, new IPComparator());
		ascCombine();
		sameCombine();
		print();
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值