ip覆盖算法

 

注释清晰,思路引导版:

import java.io.*;
import java.util.*;
public class Main{
    static class Addr{
        String addrStr;
        int mask;
        int addr;
        public Addr(String addrStr, int mask, int addr){this.addrStr = addrStr; this.mask = mask; this.addr = addr;}
    }
    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        LinkedList<Addr> list = new LinkedList<>();
        while(n-->0){
            String addrStr = br.readLine();//192.168.0.0/16
            String[] strs = addrStr.split("/");//[192.168.0.0,16]
            int mask = Integer.parseInt(strs[1]);//16
            strs = strs[0].split("\\.");//[192,168,0,0]
            //下面一句话含义就是将各个位置【最后一位二进制8位不懂,倒数第二位应该在倒数八位后所以向左移动8位,一次类推构建成ip,然后使用|合并(因为不同ip位数对应位置都是0,因此使用|来连接)】
            int addr = (Integer.parseInt(strs[0])<<24) | (Integer.parseInt(strs[1])<<16) | (Integer.parseInt(strs[2])<<8) | Integer.parseInt(strs[3]);
            boolean flag = true;
            //遍历列表,如果发现有我已经可以覆盖某个,那么移除它,如果发现我已经被覆盖了,那么直接退出就好了
            for(Iterator<Addr> it = list.iterator(); it.hasNext(); ){
                Addr tmp = it.next();
                //如果我覆盖的更广,并且【异或,相同为0,不同为1】找出不同的,向右移动我可以32-mask位,【如mask为1的时候,我只需要考虑第一位进制就好,后面31位都不需要考虑】
                //我覆盖的更广,并且和我前几位是相同的
                if(mask < tmp.mask && ( (addr ^ tmp.addr) >>> (32-mask) == 0) ) it.remove();
                //覆盖是相同的,但是我覆盖的面比当前列表中有的小,那么不需要将我加进去了
                //这里判断如果我本身覆盖面小(也就是mask大) 并且列表中的这个可以满足覆盖我(注意是列表中的,这里32减去的是item.mask)
                if(mask >= tmp.mask && ( (addr ^ tmp.addr) >>> (32-tmp.mask) == 0) ){flag = false; break;}
            }
            if(flag) list.add(new Addr(addrStr,mask,addr));
        }
        System.out.println(list.size());
        for(Iterator<Addr> it = list.iterator(); it.hasNext(); ){
            Addr tmp = it.next();
            System.out.println(tmp.addrStr);
        }
    }
}

无注释,个人精简版:

import java.util.LinkedList;
import java.util.Scanner;

public class Main03 {
    static class Addr{
        String ipStr;
        int mask;
        int addr;

        public Addr(String ipStr, int mask, int addr) {
            this.ipStr = ipStr;
            this.mask = mask;
            this.addr = addr;
        }
    }
    public static void main(String[] args) {
        Scanner s=new Scanner(System.in);
        while (s.hasNext()){
            int k=s.nextInt();
            LinkedList<Addr> resList=new LinkedList<>();
            while (k-->0){
                String ipStr=s.next();
                String[] strs=ipStr.split("/");
                int mask=Integer.parseInt(strs[1]);//可以覆盖的数量
                strs=strs[0].split("\\.");//每一项就是一块ip地址
                int addr=(Integer.parseInt(strs[0])<<24)|(Integer.parseInt(strs[1])<<16)|(Integer.parseInt(strs[2])<<8)|(Integer.parseInt(strs[3]));
                boolean isNeedAdd=true;//是否需要将这个加进去
                LinkedList<Addr> removeList=new LinkedList<>();
                for (Addr item : resList) {
                    if(mask<item.mask&&((addr^item.addr)>>(32-mask)==0))removeList.add(item);//使用for( : )不能直接移除,否则会报异常,但是使用iterator可以哦
                    //这里判断如果我本身覆盖面小(也就是mask大) 并且列表中的这个可以满足覆盖我(注意是列表中的,这里32减去的是item.mask)
                    if(mask>=item.mask&&((addr^item.addr)>>(32-item.mask)==0)){
                        isNeedAdd=false;
                        break;
                    }
                }
                for (Addr addr1 : removeList) {
                    resList.remove(addr1);
                }
                if(isNeedAdd){
                    resList.add(new Addr(ipStr,mask,addr));
                }
            }
            System.out.println(resList.size());
            for (Addr item : resList) {
                System.out.println(item.ipStr);
            }
        }
    }
}

 

posted @ 2020-08-20 22:42  程序杰杰  阅读(322)  评论(0编辑  收藏  举报