CCF CSP认证 201812-3 CIDR合并 (01Trie) (100分)
所有的ip前缀可以构成一棵01Trie,每个ip地址对应Trie上的一棵叶子结点,那么题意就是选出尽可能少的结点,使其子树中包含所有给出前缀的叶子结点,dp即可
非标准解法,没看提示,被卡内存了很难受~~
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=4e7+10,inf=0x3f3f3f3f; 5 int n,ch[N][2],ed[N],tot; 6 int newnode() {int u=++tot; ch[u][0]=ch[u][1]=ed[u]=0; return u;} 7 typedef vector<string> Vec; 8 Vec split(string S,char C) { 9 Vec vec; 10 string s; 11 for(char c:S) { 12 if(c!=C)s.push_back(c); 13 else vec.push_back(s),s.clear(); 14 } 15 vec.push_back(s),s.clear(); 16 return vec; 17 } 18 int rev(int x,int n) {int ret=0; for(int i=0; i<n; ++i)ret=ret<<1|(x>>i&1); return ret;} 19 int keep(int x,int d) {return x&((1<<d)-1);} 20 struct IP {int x,l;}; 21 IP strtoIP(string s) { 22 Vec vec=split(s,'/'); 23 int l=-1; 24 if(vec.size()==2)sscanf(vec[1].c_str(),"%d",&l); 25 vec=split(vec[0],'.'); 26 if(l==-1)l=8*vec.size(); 27 int x=0; 28 for(int i=0; i<vec.size(); ++i) { 29 int y; 30 sscanf(vec[i].c_str(),"%d",&y); 31 x|=rev(y,8)<<(8*i); 32 } 33 return {x,l}; 34 } 35 string IPtostr(IP ip) { 36 int a[4]; 37 char buf[25]; 38 for(int i=0; i<4; ++i)a[i]=rev(keep(ip.x>>(8*i),8),8); 39 sprintf(buf,"%d.%d.%d.%d/%d",a[0],a[1],a[2],a[3],ip.l); 40 return string(buf); 41 } 42 void ins(IP ip) { 43 int u=1; 44 for(int i=0; i<ip.l; ++i) { 45 int f=ip.x>>i&1; 46 if(!ch[u][f])ch[u][f]=newnode(); 47 u=ch[u][f]; 48 } 49 ed[u]=1; 50 } 51 void dfs1(int u) { 52 if(!u)return; 53 dfs1(ch[u][0]),dfs1(ch[u][1]); 54 ed[u]=ed[u]||(ed[ch[u][0]]&&ed[ch[u][1]]); 55 } 56 void dfs2(int u,IP ip) { 57 if(!u)return; 58 if(ed[u]) {cout<<IPtostr(ip)<<endl; return;} 59 dfs2(ch[u][0], {ip.x,ip.l+1}),dfs2(ch[u][1], {ip.x|(1<<ip.l),ip.l+1}); 60 } 61 62 int main() { 63 scanf("%d",&n); 64 char buf[100]; 65 tot=0,newnode(); 66 while(n--) { 67 scanf("%s",buf); 68 string s=buf; 69 IP ip=strtoIP(s); 70 ins(ip); 71 } 72 dfs1(1); 73 dfs2(1, {0,0}); 74 return 0; 75 }