CCF201812-3-CIDR合并

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xbb224007/article/details/86537821

(一)题面:

样例输入

2
           1
           2

样例输出

1.0.0.0/8
            2.0.0.0/8

样例输入

2
           10/9
           10.128/9

样例输出

10.0.0.0/8

扫描二维码关注公众号,回复: 5302481 查看本文章

样例输入

2
           0/1
           128/1

样例输出

0.0.0.0/0

 

(二)题意:

(中文题见题面)

 

(三)题解:

1、直接按照提示的步骤来写即可。

2、首先将非标准的ip标准化,这样便于处理,最后输出也是需要标准格式输出的。

3、标准化以后排序,到这里就可以拿60分了。

4、从小到大合并,这个步骤只需要判断后一个集合是否前一个集合的子集,然后合并一下即可,比较简单,做完有80分。

5、同级和并,这里类似于区间的合并,由于此时不存在完全包含的情况,故判断较为简单,具体的步骤按照提示来写即可,其中具体的原因仔细分析一下也不难得出。

6、具体的细节见代码。

(四)代码:

#include<iostream>
#include<iomanip>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#define uint unsigned long long
using namespace std;
const int maxn=1e6+10;
string D_T_S(int d){                      //数字->string
    string s=d?"":"0";
    while(d)s=s+(char)(d%10+'0'),d/=10;
    reverse(s.begin(),s.end());return "/"+s;
}
struct IP{
    string ip;uint a[5],val;
    bool operator < (const IP &p)const{  //重载比较运算符
        for(int i=0;i<5;i++)
            if(a[i]!=p.a[i])return a[i]<p.a[i];
    }                                    //同级合并时得到a'
    void init(uint b[5],uint _val,string _ip){
        for(int i=0;i<5;i++)a[i]=b[i];val=_val;
        a[4]--;ip=_ip.substr(0,_ip.find('/'))+D_T_S(a[4]);
    }
    void norm(){                         //标准化
        int l=ip.length(),pt=0,xt=0;
        for(int i=0;i<l;i++)
            if(ip[i]=='.')pt++;
            else if(ip[i]=='/')xt++;
        string ft=ip.substr(0,ip.find('/'));
        string lt=xt?ip.substr(ip.find('/'),l):"";
        for(int i=pt;i<3;i++)ft=ft+".0";
        ft=ft+(xt?lt:D_T_S((pt+1)*8));ip=ft;
    }
    void info(){                         //分离具体信息
        int l=ip.length();
        for(int i=0,t=0,s=0;i<l;i++,s=0){
            while(i<l&&ip[i]!='.'&&ip[i]!='/')
                s=s*10+ip[i++]-'0';
            a[t++]=s;
        }val=0;
        for(int i=0;i<4;i++)val=val*256+a[i];
    }
    bool legal(){                        //判断合法性
        return a[4]<33&&val>>(32-a[4])<<(32-a[4])==val;
    }
    void interval(uint &l,uint &r){      //一个ip地址所匹配的所有地址区间
        l=val>>(32-a[4])<<(32-a[4]);
        r=val|((1ull<<(32-a[4]))-1);
    }
}v[maxn];int sz;
bool sub_union(IP ip1,IP ip2,IP &res){   //判断两个同级的集合是否能合并
    IP ap;ap.init(ip1.a,ip1.val,ip1.ip);
    if(!ap.legal())return 0;
    uint apl,apr,al,ar,bl,br;
    ip1.interval(al,ar);
    ip2.interval(bl,br);
    ap.interval(apl,apr);
    if(bl<=ar+1&&al==apl&&br==apr){res=ap;return 1;}
    return 0;
}
void Union1(){                           //第二步--从小到大合并
    int p=0;
    for(int i=1;i<sz;i++){
        uint al,ar,bl,br;
        v[p].interval(al,ar);
        v[i].interval(bl,br);
        if(!(al<=bl&&br<=ar))v[++p]=v[i];
    }sz=p+1;
}
void Union2(){                           //第三步--同级合并
    int p=0;IP res;
    for(int i=1;i<sz;i++){
        if(sub_union(v[p],v[i],res)){
            v[p]=res;
            while(p>0&&sub_union(v[p-1],v[p],res))v[--p]=res;
        }else v[++p]=v[i];
    }sz=p+1;
}
int main(){                              //主函数
    cin.tie(0);
    ios_base::sync_with_stdio(0);
    int n;cin>>n;
    for(int i=0;i<n;i++){
        cin>>v[i].ip;
        v[i].norm();v[i].info();
    }sort(v,v+n);sz=n;Union1();Union2();
    for(int i=0;i<sz;i++)cout<<v[i].ip<<'\n';
    return 0;
}

 

(五)总结:

赛后AC,赛时0分,我真滴是服了,不知道当时写了什么QWQ。

其实那时候正好碰上期中考试,然后写代码写得比较少,这个题有是纯考验代码熟练度(个人认为),所以生疏了,平时还是要多加练习!!!

这次的第四题是真的简单,有点可惜...

猜你喜欢

转载自blog.csdn.net/xbb224007/article/details/86537821