2014 icpc 西安现场赛 I - International Collegiate Routing Contest

-0-马上上计网了,感觉没什么空再看笛卡尔树了2333来水篇博客
还一个多礼拜就要去西安当分母了。第一次当分母内心还有点小紧张2333
然后我们来看看这个强行银牌题。。
队友还是强啊,五分钟把铜牌题公式甩我脸上了然鹅QWQ
这个银牌题其实也不是很难(如果看得懂题的话)
首先把所有ip换成二进制表示,题目表示如果有效前缀相同那么他们在一个子网内。
那么怎么才算有效前缀呢。看/后面那个数字,就是从高到低这个字数位是有效位
255.255.255.255/32为例
11111111.11111111.11111111.11111111有效前缀是32位就是全部有效
那么这个子网就只有一个ip就是255.255.255.255
如果是255.255.255.255/24那就只有24位了
所以画一画的话就会发现我们255.255.255.~这个~可以从0-255都是在这个子网内的
如果把上面/24换成23
可以发现111111111.11111111.1111111有效前缀是这些
那么之后的11111111.11111111.11111110.~和11111111.11111111.11111111.~
都在这个子网的支配下,那么我们很容易想到用字典树去匹配前缀。
那么我们的目的是至少还要多少才能支配剩下的子网且不能有冲突
现在我们在字典树上看,把ip表示为a.b.c.d/e
支配这个行为其实就是在字典树a.b.c.d这条链上找到高度为e的那个点
以这个点为根节点的所有网络都被这个子网支配
有链就说明以当前这个前缀为子网的话下面还有已存在的子网,会产生冲突
那么我们不产生冲突的话就要找到当前网络不存在的子网
也就是在字典树上找到还没有建的节点,那么就可以直接遍历整棵字典树
如果碰到没有建的节点,那么说明这个节点可以支配一个不会产生冲突的子网
这是我们需要的
如果碰到一个节点是有效前缀的末尾,那么这之后的所有子网都被这个前缀支配所以不需要添加子网
最后输出就行了2333

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 8;

struct Tire
{
    int mark;
    int next[2];
}t[N];
struct IP
{
    int ip[40];
};
int tot = 0;
int x[40];
int root;

int NewNode()
{
    tot ++;
    t[tot].mark = 0;
    for(int i = 0;i<2;i++)
        t[tot].next[i] = 0;
    return tot;
}
void init()
{
    memset(t,0,sizeof(t));
    tot = 0;
    root = NewNode();
}
void ip2str(int a,int b,int c,int d,int e)
{
    memset(x,0,sizeof(x));
    for(int i = 7;i>=0;i--)
    {
        x[i] = a % 2;
        a /= 2;
    }
    for(int i = 15;i >= 8;i--)
    {
        x[i] = b % 2;
        b /= 2;
    }
    for(int i = 23;i >= 16;i--)
    {
        x[i] = c % 2;
        c /= 2;
    }
    for(int i = 31;i >= 24;i--)
    {
        x[i] = d % 2;
        d /= 2;
    }
    x[32] = e;
}
void insert()
{
    int pos = x[32];
    int r = root;
    for(int i = 0;i<32;i++)
    {
        if(!pos)
        {
            t[r].mark = 1;  
            return;
        }
        //printf("%d %d %d\n",i, x[i],r);
        if(!t[r].next[x[i]])
        {
            int temp = NewNode();
            t[r].next[x[i]] = temp;
        }
        r = t[r].next[x[i]];
        pos --;
    }
}
vector<IP>ans;
int tar[40];
void dfs(int r,int d)
{
    if(d > 32)
        return;
    if(!r)
    {
        IP temp;
        for(int i = 0;i<33;i++)
            temp.ip[i] = tar[i];
        temp.ip[32] = d;
        ans.push_back(temp);
        return;
    }
    if(t[r].mark)
        return;
    tar[d] = 0;
    dfs(t[r].next[0],d+1);
    tar[d] = 1;
    dfs(t[r].next[1],d+1);
    tar[d] = 0;
}
void PrintIp(IP x)
{
    int a,b,c,d,e;
    a = b = c = d = e = 0;
    for(int i = 0;i<8;i++)
    {
        a *= 2;
        a += x.ip[i];
    }
    for(int i = 8;i<16;i++)
    {
        b *= 2;
        b += x.ip[i];
    }
    for(int i = 16;i<24;i++)
    {
        c *= 2;
        c += x.ip[i];
    }
    for(int i = 24;i<32;i++)
    {
        d *= 2;
        d += x.ip[i];
    }
    e = x.ip[32];
    printf("%d.%d.%d.%d/%d\n",a,b,c,d,e);
}
int main()
{
    int T;
    scanf("%d",&T);
    int ka = 0;
    while(T--)
    {
        int n;
        scanf("%d",&n);
        init(); 
        for(int i = 0;i<n;i++)
        {
            int a,b,c,d,e;
            scanf("%d.%d.%d.%d/%d",&a,&b,&c,&d,&e);
            ip2str(a,b,c,d,e);
            insert();
        }   
        ans.clear();
        memset(tar,0,sizeof(tar));
        dfs(root,0);
        printf("Case #%d:\n",++ka);
        if(n == 0)
        {
            printf("1\n");
            printf("0.0.0.0/0\n");
            continue;
        }
        printf("%d\n",ans.size());
        for(int i = 0; i != ans.size(); i ++)
            PrintIp(ans[i]);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值