CCF 201812-3 CIDR合并(90分--运行超时)

易错点:

这道题思路题目已给出,但是易错点有点多,列举一些自己遇到的坑:
1.使用vector容器,由于是顺序表,删除插入操作较多,导致运行超时,用list链表可以做到100分,之后补上;已写好(链接: CCF 20181203 CIDR合并–vector排序+list合并
2.比较排序时一定要是数字比较,而不是字符串比较,后者会出错;
3.同级合并时,一定要判断新合成的前缀是否合法,即后缀是否全部为0;(其实也就是后一位不能是1)
4.完成第一步排序可得60分,完成从小到大吞并可得80分,完成同级合并且不超时的情况下可得100,否则视超时情况。

#include<bits/stdc++.h>
using namespace std;

struct node{
	int ip[4];
	int len;
};
vector<node> vip;

inline bool cmp(node a,node b){
	for(int i=0;i<4;i++){
		if(a.ip[i]!=b.ip[i])return a.ip[i]<b.ip[i];
	}
	return a.len<b.len;
}

inline bool compare(node a,node b){           //比较吞并函数
	int piror=8-a.len%8;
	int range=pow(2,piror)-1;
	int t=a.len/8;
	for(int i=0;i<t;i++){
		if(a.ip[i]!=b.ip[i])return false;
	}
	if(b.ip[t]<=a.ip[t]+range){
		return true;
	}
	return false;
}


inline bool combine(node a,node b,node &neo){         //合并函数
	if(a.len!=b.len)return false;
	neo.len=a.len-1;
	for(int i=0;i<4;i++){
		neo.ip[i]=a.ip[i];
	}
	if(compare(neo,a)&&compare(neo,b)){
		int piror=8-neo.len%8;
     	int range=pow(2,piror)/2;
     	int t=neo.len/8;
     	int m=pow(2,piror);
     	if(neo.ip[t]%m!=0)return false ;//判断neo是否合法 
     	for(int i=0;i<t;i++){
     		if(a.ip[i]!=b.ip[i])return false;
	    }
    	if(b.ip[t]==a.ip[t]+range){
    		return true;
    	}
    	return false;
	}
}

inline void table(string str){                //制表
    node temp;
	int p=str.find('/'),i=0;
	temp.len=stoi(str.substr(p+1));
	str=str.substr(0,p);
	while((p=str.find('.'))!=-1){
		str[p]=' ';
	}
	stringstream ss;
	string s;
	ss<<str;
	while(ss>>s){
		temp.ip[i++]=stoi(s);
	}
	vip.push_back(temp);
}

inline void standard(string &str){            //IP标准化 
	int t=3,flag=1,p;
	for(int i=0;i<str.size();i++){
		if(str[i]=='.')t--;
		if(str[i]=='/')flag=0;
	}
	if(flag){
		int len=(4-t)*8;
		str=str+"/"+to_string(len);
	}
	p=str.find('/');
	while(t--){
		str.insert(p,".0");
	}
}

int main(){
	ios::sync_with_stdio(false);
	//输入 
	int n;
	cin>>n;
	for(int i=0;i<n;i++){
		string str;
		cin>>str;
		//标准化
		standard(str);
		//制表
		table(str); 
	}
	//排序
	sort(vip.begin(),vip.end(),cmp);

	//从小到大吞并
	for(int i=0;i<vip.size();i++){
		if(i+1==vip.size())break;
		if(compare(vip[i],vip[i+1])){
			vip.erase(vip.begin()+i+1);
			i--;
		}
	}
	//同级合并
	for(int i=0;i<vip.size();i++){
		if(i+1==vip.size())break;
		node neo;
		if(combine(vip[i],vip[i+1],neo)){
			vip.erase(vip.begin()+i,vip.begin()+i+2);
			vip.insert(vip.begin()+i,neo);
			if(i==0)i--;
			else i=i-2;
		}
	} 
	//输出
	for(auto it:vip){
		for(int i=0;i<4;i++){
			cout<<it.ip[i];
			if(i<3)cout<<'.';
		}
		cout<<'/'<<it.len<<endl;
	}
	return 0;
} 
样例:

建议全部都要试一遍,否则很难保证算法正确性。

2
2.0.0.0/7 
4.0.0.0/7

2
1.0.0.0/8 
2.0.0.0/8

2
1.0.0.0/16 
2.0.0.0/16

2
10/9
10.128/9

2
0/1
128/1

2
101.128.0.0/10
101.192.0.0/10

2
101.6.6.0/24
101.6.7.0/24

2
101.6.6.0/24
101.6.6.128/25
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值