zoukankan      html  css  js  c++  java
  • CCF-CSP题解 201812-3 CIDR合并

    题目想求与给定前缀列表等价的包含IP前缀数目最少的前缀列表。

    首先是怎么存储前缀列表。用一个long long存储IP地址,再存一个前缀长度,封装在一个结构体里(<ipNum, len>),方便后面排序等操作。IP前缀有三种输入格式,稍微分情况讨论一下。

    接着以(ipNum)为第一关键字,(len)为第二关键字升序排序。

    然后考虑去除匹配集被其它IP前缀包含的IP前缀。考虑之前匹配集范围的上届(mmax),顺序遍历一下就好了。将剩余的IP列表按之前顺序存在一个静态链表中。

    最后将相邻的可合并的IP前缀合并,其实就是前缀长度最后一位0和1,之前完全相同即可。

    温习一下链表的插入删除操作。

    #include <bits/stdc++.h>
    typedef long long LL;
    const int maxn = 1000000;
    
    using namespace std;
    
    struct tIP
    {
        LL ipNum;
        int len;
        int before, next;
        tIP()
        {
            before = next = -1;
        }
        bool operator < (const tIP &y) const
        {
            if(ipNum == y.ipNum)
                return len < y.len;
            return ipNum < y.ipNum;
        }
        void show()
        {
            LL num[5];
            LL temp = ipNum;
            for (int i = 4; i >= 1; i--)
            {
                num[i] = temp % 256;
                temp /= 256;
            }
            for (int i = 1; i <=4; i++)
            {
                printf("%lld", num[i]);
                if (i == 4)
                    printf("/");
                else
                    printf(".");
            }
            printf("%d
    ", len);
        }
    };
    tIP ip[maxn+10];
    
    LL getMMax(tIP iip)
    {
        LL temp = (1LL << (32-iip.len)) - 1;
        return iip.ipNum | temp;
    }
    
    int main()
    {
        int n;
        scanf("%d", &n);
    
        char s[30];
        for (int id = 1, slash, dotCnt, style; id <= n; id++)
        {
            slash = 0;
            dotCnt = 0;
            scanf("%s", s + 1);
            for (int i = 1; s[i] != ''; i++)
            {
                if (s[i] == '/')
                    slash = 1;
                if (s[i] == '.')
                    dotCnt ++;
            }
    
            if (slash == 1 && dotCnt == 3)
                style = 1;
            else if (slash == 1 && dotCnt < 3)
                style = 2;
            else
                style = 3;
    
            LL num[5];
            memset(num, 0, sizeof(num));
            if (style == 1 || style == 2)
            {
                for (int i = 1, temp = 0, numCnt = 1; ; i++)
                {
                    if (s[i] == '.' || s[i] == '/')
                    {
                        num[numCnt++] = temp * 1LL;
                        temp = 0;
                    }
                    else if (s[i] == '')
                    {
                        ip[id].len = temp;
                        break;
                    }
                    else
                    {
                        temp = temp * 10 + s[i] - '0';
                    }
                }
            }
            else
            {
                for (int i = 1, temp = 0, numCnt = 1; ; i++)
                {
                    if (s[i] == '.')
                    {
                        num[numCnt++] = temp * 1LL;
                        temp = 0;
                    }
                    else if (s[i] == '')
                    {
                        num[numCnt++] = temp * 1LL;
                        ip[id].len = (numCnt-1) * 8;
                        break;
                    }
                    else
                    {
                        temp = temp * 10 + s[i] - '0';
                    }
                }
            }
            LL ans = 0;
            for (int i = 1; i <= 4; i++)
            {
                ans = ans * 256 + num[i];
            }
            ip[id].ipNum = ans;
        }
    
        sort(ip + 1, ip + 1 + n);
    
        LL mmax = -1;
        int st = 0, en = n + 1;
        ip[st].before = -1;
        ip[st].next = en;
        ip[en].before = st;
        ip[en].next = -1;
        for (int id = 1, prev = 0; id <= n; id++)
        {
            if (ip[id].ipNum > mmax)
            {
                ip[id].before = prev;
                ip[id].next = en;
                ip[prev].next = ip[en].before = id;
                prev = id;
                mmax = getMMax(ip[id]);
            }
        }
    
        int pNow = ip[0].next;
        while (pNow != en)
        {
            int p1 = pNow, p2 = ip[pNow].before;
            if (p2 == 0)
                pNow = ip[pNow].next;
            else
            {
                if (ip[p1].len == ip[p2].len &&
                    (ip[p2].ipNum & (1LL << (32-ip[p2].len))) == 0 &&
                    (ip[p2].ipNum | (1LL << (32-ip[p2].len))) == ip[p1].ipNum)
                {
                    ip[p1].before = ip[p2].before;
                    ip[ip[p1].before].next = p1;
                    ip[p1].ipNum = ip[p2].ipNum;
                    ip[p1].len --;
                }
                else
                {
                    pNow = ip[pNow].next;
                }
            }
        }
    
        pNow = ip[0].next;
        while (pNow != en)
        {
            ip[pNow].show();
            pNow = ip[pNow].next;
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    【乱侃】How do they look them ?
    【softeware】Messy code,some bug of Youdao notebook in EN win7
    【随谈】designing the login page of our project
    【web】Ad in security code, making good use of resource
    SQL数据库内存设置篇
    关系数据库的查询优化策略
    利用SQL未公开的存储过程实现分页
    sql语句总结
    sql中使用cmd命令注销登录用户
    SQLServer 分页存储过程
  • 原文地址:https://www.cnblogs.com/acboyty/p/11363132.html
Copyright © 2011-2022 走看看