Gym - 100548I International Collegiate Routing Contest (01字典树)

版权声明:Why is everything so heavy? https://blog.csdn.net/lzc504603913/article/details/84146363

题意:给你多个子网掩码,要你求一个最小的子网掩码补集。

解题思路: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;
}

猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/84146363