1. 程式人生 > 實用技巧 >CCF CSP認證 201812-3 CIDR合併 (01Trie)

CCF CSP認證 201812-3 CIDR合併 (01Trie)

所有的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 }