UVALive 7043 International Collegiate Routing Contest(字典树)

题意:

输入IPv4地址空间中的一些子网号,构成一个网络集合。
输出个数最小的一个网络集合,要求其与输入集合没有交集,且相对与IPv4地址空间全集,与输入集合互为补集。
输出集合包含的子网号,格式遵循网络规范。

解析:

这题可以用Trie树来搞。
每个IP地址由32位二进制组成。整个地址空间可以表现为一棵二叉树。
用Trie的节点标记每个二进制串所能抵达的终点,即子网覆盖的终点位置。
建立Trie树后,DFS遍历树上的分支,输出没有被覆盖的分支即可。

my code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#define pb push_back
using namespace std;
typedef long long ll;

const int maxnode = (int)5e5  + 10;
const int sigma_size = 2;

vector<string> ans;

struct Trie {
    int ch[maxnode][2];
    bool val[maxnode];
    int sz;

    void clear() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); }
    Trie() { clear(); }
    int idx(char c) { return c - '0'; }

    void insert(char* s, int len) {
        int u = 0;
        for(int i = 0; i < len; i++) {
            int c = idx(s[i]);
            if(!ch[u][c]) {
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = false;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = true;
    }

    void setIp(ll ip, int len) {
        int a[4];
        char buf[30];
        for(int i = 3; i >= 0; i--) {
            a[i] = ip % 256;
            ip >>= 8;
        }
        sprintf(buf, "%d.%d.%d.%d/%d", a[0], a[1], a[2], a[3], len+1);
        ans.pb(buf);
    }

    void dfs(int u, int dep, ll cur) {
        if(val[u]) return;
        for(int i = 1; i >= 0; i--) {
            ll ip = cur | ((ll)i << (31-dep));
            if(!ch[u][i])
                setIp(ip, dep);
            else
                dfs(ch[u][i], dep+1, ip);
        }
    }
} trie;

int n;
char bit[33];
void trans(char* s, ll ip) {
    for(int i = 31; i >= 0; i--)
        s[31-i] = ((ip >> i) & 1) + '0';
    s[32] = '\0';
}

ll getIp(ll a, ll b, ll c, ll d) {
    return (1LL << 24) * a + (1LL<<16) * b + (1LL<<8) * c + d;
} 

int main() {
    int T, cas = 1;
    scanf("%d", &T);
    while(T--) {
        trie.clear();
        ans.clear();

        scanf("%d", &n);
        printf("Case #%d:\n", cas++);
        if(n == 0) {
            puts("1\n0.0.0.0/0");
            continue;
        }

        ll a, b, c, d, len, ip;
        for(int i = 0; i < n; i++) {
            scanf("%lld.%lld.%lld.%lld/%lld", &a, &b, &c, &d, &len);
            ip = getIp(a, b, c, d);
            trans(bit, ip);
            trie.insert(bit, len);
        }
        trie.dfs(0, 0, 0);

        int size = ans.size();
        printf("%d\n", size);
        for(int i = 0; i < size; i++) {
            printf("%s\n", ans[i].c_str());
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值