CIDR合并(CCF 201812-3)

最终的100分代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

class IP{
	int[] value;
	int mask;
	
	public IP() {
		this.value = new int[4];
		for(int i=0;i<4;i++) {
			this.value[i]=0;
		}
	}

	@Override
	public String toString() {
		return value[0]+"."+value[1]+"."+value[2]+"."+value[3]+"/"+mask;
	}

}

public class Main {

	public static void main(String[] args) throws IOException{
		
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(bf.readLine());
		String rawIp;
		// 转换为标准形式
		ArrayList<IP> ipArr = new ArrayList<IP>();
		for(int i=0;i<n;i++) {
			rawIp = bf.readLine();
			ipArr.add(toIp(rawIp));
		}
		
		// 排序
		Collections.sort(ipArr, new Comparator<IP>() {
			@Override
			public int compare(IP o1,IP o2) {
				int flag = greaterThan(o1,o2);
				if(flag==0) {
					// 前缀长度
					if(o1.mask>o2.mask) {
						flag = 1;
					}else {
						flag = -1;
					}
				}
				return flag;
			}
		});
		
		IP[] newArr = new IP[ipArr.size()];            // 转为数组
		boolean[] delete = new boolean[ipArr.size()];  // 是否被删除
		ipArr.toArray(newArr);
		
		int relation;
		int right = 0;
		int len = newArr.length;
		boolean flag = false;
		for(int i=0;i<len-1;) {
			// 删除跳过
			if(delete[i]) {
				i++;
				continue;
			}

			// 找到右边一个
			do {
				right++;
				if(right>=len) {
					flag = true;
					break;
				}
			}while(delete[right] || right==i);
			if(flag) {
				break;
			}

			relation = relation(newArr[i],newArr[right]);

			if(relation==1) {
				// 包含
//				System.out.println("吞 "+newArr[i]+" <- "+newArr[right]+" 删"+right);
				delete[right] = true;
			}else if(relation==2) {
				// 合并
//				System.out.println("合 "+newArr[i]+" & "+newArr[right]+" 删"+right);
				newArr[i].mask -= 1;
				delete[right] = true;
				if(i>0) {
					right=i-1;
					i--;
					while(delete[i]) {
						i--;
					}
				}
			}else {
				i++;
			}
		}

		for(int i=0;i<newArr.length;i++) {
			if(!delete[i]) {
				System.out.println(newArr[i]);
			}
		}
	}
	
	// 包含返回1,合并返回2
	public static int relation(IP a,IP b) {

		if(a.mask<=b.mask) {
			int part = (a.mask-1)/8;
			int digit = a.mask - part*8;
			
			for(int i=0;i<part;i++) {
				if(a.value[i]!=b.value[i]) {
					return 0;
				}
			}
			
			int ap = a.value[part] >> (8-digit);
			int bp = b.value[part] >> (8-digit);

			if(ap==bp) {
				return 1;
			}
			
			if(a.mask==b.mask && bp-ap==1 && ((ap>>1)==(bp>>1))) {
				return 2;
			}

		}
		
		return 0;
	}
	
	// 比较两个IP
	public static int greaterThan(IP o1,IP o2) {	
		int flag = 1;
		
		int a = (o1.value[0]<<8) + o1.value[1] - (o2.value[0]<<8) - o2.value[1];
		
		if(a>0) {
		}else if(a<0) {
			flag = -1;
		}else {
			int b = (o1.value[2]<<8) + o1.value[3] - (o2.value[2]<<8) - o2.value[3];
			flag = b;
		}
		
		return flag;
	}
	
	// 处理输入的ip
	public static IP toIp(String rawIp) {
		int split = rawIp.indexOf('/');
		String value = rawIp;
		int mask = 0;
		// 含有'/',分割
		if(split>0) {
			value = rawIp.substring(0, split);
			mask = Integer.parseInt(rawIp.substring(split+1, rawIp.length()));
		}

		IP ip = new IP();
		ip.mask = mask;
		
		// 处理地址
		for(int i=0;i<4;i++) {
			if(value.contains(".")) {
				// 继续分割
				split = value.indexOf('.');
				ip.value[i] = Integer.parseInt(value.substring(0,split));
				value = value.substring(split+1,value.length());
			}else if(value.length()>0) {
				// 只有数字
				ip.value[i] = Integer.parseInt(value);
				value = "";
				// 若无前缀长度
				if(ip.mask==0) {
					ip.mask = (i+1)*8;
				}
			}else {
				// 空
				ip.value[i] = 0;
			}
		}
		
		return ip;
	}
	
}

踩的两个最大的坑:

  1. 同级合并的细节
  2. 超时

悲惨的改代码过程:

第一步,处理不同格式ip输入
测试输入

7
101.6.6.0/24
101.6.6/23
101/8
1/32
101.6.6.0
101.6
1

标准形式

101.6.6.0/24
101.6.6.0/23
101.0.0.0/8
1.0.0.0/32
101.6.6.0/32
101.6.0.0/16
1.0.0.0/8

第二步,排序

1.0.0.0/8
1.0.0.0/32
101.0.0.0/8
101.6.0.0/16
101.6.6.0/23
101.6.6.0/24
101.6.6.0/32

此时提交可通过测试点1-4,有60分

下一步,从小到大合并,80分

最后一步,同级合并

测试1

输入

4
206.0.68.0/25
206.0.68.128/25
206.0.69.0/25
206.0.69.128/25

输出

206.0.68.0/23
测试2

输入

12
206.0.68.0/25
206.0.68.128/25
206.0.69.0/25
206.0.69.128/25
206.0.70.0/26
206.0.70.64/26
206.0.70.128/26
206.0.70.192/26
206.0.71.128/26
206.0.71.64/26
206.0.71.192/26
206.0.71.0/26

输出

206.0.68.0/22
测试3

输入

3
206.0.71.64/25
206.0.71.192/26
206.0.71.0/26

这种也可以合并,不过似乎不用考虑?

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

class IP{
	int[] value;
	int mask;
	
	public IP() {
		this.value = new int[4];
		for(int i=0;i<4;i++) {
			this.value[i]=0;
		}
	}

	@Override
	public String toString() {
		return value[0]+"."+value[1]+"."+value[2]+"."+value[3]+"/"+mask;
	}

}

public class Main {

	public static void main(String[] args) {
		
		Scanner s = new Scanner(System.in);
		
		int n = Integer.parseInt(s.nextLine());
		String rawIp;
		
		// 转换为标准形式
		ArrayList<IP> ipArr = new ArrayList<IP>();
		for(int i=0;i<n;i++) {
			rawIp = s.nextLine();
			ipArr.add(toIp(rawIp));
		}
		
		// 排序
		Collections.sort(ipArr, new Comparator<IP>() {
			@Override
			public int compare(IP o1,IP o2) {
				int flag = greaterThan(o1,o2);
				if(flag==0) {
					// 前缀长度
					if(o1.mask>o2.mask) {
						flag = 1;
					}else {
						flag = -1;
					}
				}
				return flag;
			}
		});
		
		// 从小到大合并
		for(int i=0;i<ipArr.size()-1;i++) {
			if(contain(ipArr.get(i),ipArr.get(i+1))) {
				ipArr.remove(i+1);
			}
		}
		
		// 同级合并
		for(int i=0;i<ipArr.size()-1;i++) {
			if(canMerge(ipArr.get(i),ipArr.get(i+1))) {
				ipArr.get(i).mask -= 1;
				ipArr.remove(i+1);
				if(i>0) {
					i -= 2;
				}
			}
		}
		
		for(int i=0;i<ipArr.size();i++) {
			System.out.println(ipArr.get(i));
		}
	}
	
	// 检查是否可以合并
	public static boolean canMerge(IP a,IP b) {
		boolean flag = false;
		
		if(a.mask==b.mask) {
			int part = (a.mask-1)/8;
			int digit = a.mask - part*8;
			
			IP newA = new IP();
			for(int i=0;i<4;i++) {
				newA.value[i] = a.value[i];
			}
			newA.value[part] += 1<<(8-digit);
			
			if(greaterThan(newA,b)==0) {
				flag=true;
			}
		}
		
		return flag;
	}
	
	// 检查a是否包含b
	public static boolean contain(IP a,IP b) {
		boolean flag = false;
		
		if(a.mask<=b.mask) {
			IP aMax = getMaxIp(a);
			IP bMax = getMaxIp(b);
			
			if(greaterThan(b,a)>=0 && greaterThan(aMax,bMax)>=0) {
				flag = true;
			}
		}
		
		return flag;
	}
	
	// 比较两个IP
	public static int greaterThan(IP o1,IP o2) {
		int flag = 1;
		int a = (o1.value[0]*256 + o1.value[1]) - (o2.value[0]*256 + o2.value[1]);
		if(a>0) {
		}else if(a<0) {
			flag = -1;
		}else {
			int b = (o1.value[2]*256 + o1.value[3]) - (o2.value[2]*256 + o2.value[3]);
			if(b<0){
				flag = -1;
			}else if(b==0) {
				flag = 0;
			}
		}
		return flag;
	}
	
	// 根据mask获取最大IP
	public static IP getMaxIp(IP ip) {
		IP maxIP = new IP();
		
		int ms = 32-ip.mask;
		int[] m = new int[4];
		for(int i=3;i>=0;i--) {
			if(ms>=8) {
				m[i]=8;
				ms-=8;
			}else {
				m[i]=ms;
				break;
			}
		}
		
		for(int i=0;i<4;i++) {
			maxIP.value[i] = ip.value[i] + (1<<m[i]) - 1;
		}
		
		return maxIP;
	}
	
	// 处理输入的ip
	public static IP toIp(String rawIp) {
		int split = rawIp.indexOf('/');
		String value = rawIp;
		int mask = 0;
		// 含有'/',分割
		if(split>0) {
			value = rawIp.substring(0, split);
			mask = Integer.parseInt(rawIp.substring(split+1, rawIp.length()));
		}

		IP ip = new IP();
		ip.mask = mask;
		
		// 处理地址
		for(int i=0;i<4;i++) {
			if(value.contains(".")) {
				// 继续分割
				split = value.indexOf('.');
				ip.value[i] = Integer.parseInt(value.substring(0,split));
				value = value.substring(split+1,value.length());
			}else if(value.length()>0) {
				// 只有数字
				ip.value[i] = Integer.parseInt(value);
				value = "";
				// 若无前缀长度
				if(ip.mask==0) {
					ip.mask = (i+1)*8;
				}
			}else {
				// 空
				ip.value[i] = 0;
			}
		}
		
		return ip;
	}
	
}

结果:得分80,时间使用1.39s,空间使用171.7MB

把Scanner改成BufferedReader
结果:得分80,时间使用1.234s,空间使用103.4MB

难道是超时
心好痛

修改从小到大合并的方法

一些测试数据

10.0/9
10.28/18

10.0/9
10.1/9

10.0/1
10.0/32

101.6.6.0/24
101.6.7.0/24

101.6.6.0/24
101.6.6.128/24

结果:得分80,时间使用890ms,空间使用95.19MB

快了一些,但是还是80分,说明前面不是超时的问题,还是同级合并有问题

改啊改啊改

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

class IP{
	int[] value;
	int mask;
	
	public IP() {
		this.value = new int[4];
		for(int i=0;i<4;i++) {
			this.value[i]=0;
		}
	}

	@Override
	public String toString() {
		return value[0]+"."+value[1]+"."+value[2]+"."+value[3]+"/"+mask;
	}

}

public class Main {

	public static void main(String[] args) throws IOException{
		
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		
		int n = Integer.parseInt(bf.readLine());
		String rawIp;
		
		// 转换为标准形式
		ArrayList<IP> ipArr = new ArrayList<IP>();
		for(int i=0;i<n;i++) {
			rawIp = bf.readLine();
			ipArr.add(toIp(rawIp));
		}
		
		// 排序
		Collections.sort(ipArr, new Comparator<IP>() {
			@Override
			public int compare(IP o1,IP o2) {
				int flag = greaterThan(o1,o2);
				if(flag==0) {
					// 前缀长度
					if(o1.mask>o2.mask) {
						flag = 1;
					}else {
						flag = -1;
					}
				}
				return flag;
			}
		});
		
		int relation;
		for(int i=0;i<ipArr.size()-1;) {
			relation = relation(ipArr.get(i),ipArr.get(i+1));
			if(relation==1) {
//				System.out.println("吞 "+ipArr.get(i)+" <- "+ipArr.get(i+1));
				ipArr.remove(i+1);
			}else if(relation==2) {
//				System.out.println("合 "+ipArr.get(i)+" & "+ipArr.get(i+1));
				ipArr.get(i).mask -= 1;
				ipArr.remove(i+1);
				if(i>0) {
					i--;
				}
			}else {
				i++;
			}
		}

		for(int i=0;i<ipArr.size();i++) {
			System.out.println(ipArr.get(i));
		}
	}
	
	// 包含返回1,合并返回2
	public static int relation(IP a,IP b) {
		
		if(a.mask<=b.mask) {
			int part = (a.mask-1)/8;
			int digit = a.mask - part*8;
			
			for(int i=0;i<part;i++) {
				if(a.value[i]!=b.value[i]) {
					return 0;
				}
			}
			
			int ap = a.value[part] >> (8-digit);
			int bp = b.value[part] >> (8-digit);
			
			if(ap==bp) {
				return 1;
			}
			
			if(a.mask==b.mask && bp-ap==1 && ((ap>>1)==(bp>>1))) {
				return 2;
			}

		}
		
		return 0;
	}
	
	// 比较两个IP
	public static int greaterThan(IP o1,IP o2) {
		int flag = 1;
		int a = (o1.value[0]*256 + o1.value[1]) - (o2.value[0]*256 + o2.value[1]);
		if(a>0) {
		}else if(a<0) {
			flag = -1;
		}else {
			int b = (o1.value[2]*256 + o1.value[3]) - (o2.value[2]*256 + o2.value[3]);
			if(b<0){
				flag = -1;
			}else if(b==0) {
				flag = 0;
			}
		}
		return flag;
	}
	
	// 处理输入的ip
	public static IP toIp(String rawIp) {
		int split = rawIp.indexOf('/');
		String value = rawIp;
		int mask = 0;
		// 含有'/',分割
		if(split>0) {
			value = rawIp.substring(0, split);
			mask = Integer.parseInt(rawIp.substring(split+1, rawIp.length()));
		}

		IP ip = new IP();
		ip.mask = mask;
		
		// 处理地址
		for(int i=0;i<4;i++) {
			if(value.contains(".")) {
				// 继续分割
				split = value.indexOf('.');
				ip.value[i] = Integer.parseInt(value.substring(0,split));
				value = value.substring(split+1,value.length());
			}else if(value.length()>0) {
				// 只有数字
				ip.value[i] = Integer.parseInt(value);
				value = "";
				// 若无前缀长度
				if(ip.mask==0) {
					ip.mask = (i+1)*8;
				}
			}else {
				// 空
				ip.value[i] = 0;
			}
		}
		
		return ip;
	}
	
}

呜呜呜90了
终于把同级合并改对了

看看还能不能快一点

把最后的遍历从链表改成了数组,成功!

awsl

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值