201812-3 CIDR合并

201812-3 CIDR合并

题解思路

计算包含IP前缀数目最少的等价前缀列表
第一步:排序
将所有IP前缀进行排序,以其IP地址为第一关键字,以前缀长度为第二关键字从小到大排序,形成一个列表。
第二步:从小到大合并
从头到尾扫描该列表,依次考虑其相邻的两个元素a,b:如果b的匹配集是a的匹配集的子集,则将b从列表中移除。如果b后仍有元素c,则此时a与c变为相邻的元素,应当继续考虑这对新的相邻元素,直到a的下一个元素不能被移除。然后继续依次处理列表中接下来的相邻元素。
可以证明,在此躺扫描结束之后,列表中不会存在任何两个元素a,b使得b的匹配集是a的匹配集的子集。
第三步:同级合并
从头到尾扫描该列表,依次考虑其相邻的两个元素a,b:如果a与b的前缀长度相同,则设a’为一个新的IP前缀,其IP地址与a相同,而前缀长度比a少1。如果a’合法且a的匹配集与b的匹配集的并集等于a’的匹配集,则将a与b从列表中移除,并将a’插入到列表中原来a,b的位置。与上一步不同的是,如果a’之前存在元素,则接下来应当从a’的前一个元素开始考虑;否则继续从a’开始考虑。

由于这道题对时间卡得紧,需要在同级合并那里使用链表优化,不然会超时

#include
#include
#include

using namespace std;
typedef long long ll;
const int N=1e6+10;
long long P[34]; //保存2的幂次 P[i]=2^(33-i)

struct IP
{
    ll s;
    int len;
    bool operator < (const IP &u) const
    {
        if(su.s) return false;
        else return lenb.len) return false;//a的前缀长度比b的长,显然b不是a的子集
    if(a.s/P[a.len+1]!=b.s/P[a.len+1]) return false;//a的前缀长度比b的短,判断前缀是否相等
    else return true;//输出b是a的子集
}

int l[N];//第三步同级合并时使用
string ans[N];//记录输出结果

int main()
{
    P[33]=1;
    for(int i=32;i>=0;i--){
        P[i]=2*P[i+1];
        //P[32]=2*P[33]=2
        //P[31]=2*P[32]=2*2*P[33]=2^2=2^(33-31)
        //P[30]=2*P[31]=2*2*2*P[33]=2^3=2^(33-30)
        //P[0]=2^33
        //P[i]=2^(33-i)
    }

    int n;
    cin>>n;
    if(n==0) return 0;

    string str;
    //输入n条IP前缀并转换格式(IP地址由点分十进制转换为十进制)
    for(int k=0;k>str;
        int t=0,num1=0,num2=0;//num1={0,1,2,3},记录IP地址位段数目(num1+1),num2={0,1},记录是否省略IP前缀长度
        ll ret=0;
        for(int i=0;inum1;i--)
                ret=ret*256;
        }
        if(!num2) ip[k].len=(num1+1)*8;//num2为0时省略长度还需记录前缀长度为(num1+1)*8
        ip[k].s=ret;//记录IP地址的值
        //cout<=0;k--)
                ans[cnt]+=s[k];
            if(j==4) break;
            ans[cnt]+=".";
        }
        ans[cnt]+='/';
        t=ip[i].len;
        string s="";
        do
        {
            s+='0'+t%10;
            t/=10;
        }while(t);
        for(int k=s.length()-1;k>=0;k--)
            ans[cnt]+=s[k];
        cnt++;
    }

    //输出
    for(int i=cnt-1;i>=0;i--)
        cout<

参考博客

你可能感兴趣的:(CCF)