1. 程式人生 > >100548I International Collegiate Routing Contest (01字典樹)

100548I International Collegiate Routing Contest (01字典樹)

題意:給你多個子網掩碼,要你求一個最小的子網掩碼補集。

解題思路:IPV4一共有 2^32個地址,實際上對應的就是一個完全字典樹。現在給定的子網掩碼,實際上就是給定了一個字典樹,然後要你求這個字典樹的補樹,使得是一個完全字典樹。實際上就是求這個字典樹的所有補樹形成的森林。

那麼我們只要深搜即可。然後記錄下答案,然後還原下答案即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
const int MAXN=200050;

int nxt[MAXN][2];
int sta[MAXN];
int tot=1;
int root=1;
int mask;

void insert(uint x){
    int cur=root;
    for(int i=31;i>=31-mask+1;i--){
        uint c=((x>>i)&1);
        if(nxt[cur][c]==0)
            nxt[cur][c]=++tot;
        cur=nxt[cur][c];
        
    }
    sta[cur]=1;
}

vector<pair<uint,int> > ans;
void dfs(int u,int dep,uint sum){
    if(u==0)//證明沒有覆蓋到
    {
        ans.push_back({sum,dep});
        return;
    }
    if(sta[u]==1)//後面就不用深搜了
    {
        return;
    }
    dfs(nxt[u][0],dep+1,sum<<1);
    dfs(nxt[u][1],dep+1,(sum<<1)+1);
}

int main(){
    
    int T;
    scanf("%d",&T);
    for(int qqq=1;qqq<=T;qqq++){
        tot=1;
        root=1;
        memset(nxt,0,sizeof(nxt));
        memset(sta,0,sizeof(sta));
        int N;
        scanf("%d",&N);
        if(N==0)//特判
        {
            printf("Case #%d:\n",qqq);
            printf("%d\n",1);
            printf("%d.%d.%d.%d/%d\n",0,0,0,0,0);
            continue;
        }
        int a,b,c,d;
        ans.clear();
        for(int i=0;i<N;i++)
        {
            scanf("%d.%d.%d.%d/%d",&a,&b,&c,&d,&mask);
            uint sum=a;//加密
            sum<<=8;
            sum+=b;
            sum<<=8;
            sum+=c;
            sum<<=8;
            sum+=d;
            insert(sum);
        }
        
        dfs(root,0,0);
        
        printf("Case #%d:\n",qqq);
        printf("%d\n",ans.size());
        
        for(int i=0;i<ans.size();i++){
            uint s=ans[i].first;
            int dd=ans[i].second;
            s<<=(32-dd);//解密
            a=(s>>24);
            b=(s>>16)%(1<<8);
            c=(s>>8)%(1<<8);
            d=s%(1<<8);
            printf("%d.%d.%d.%d/%d\n",a,b,c,d,dd);
        }
    }

    return 0;
}