西安现场赛 Problem I. International Collegiate Routing Contest

题目大意:

给你一些ip地址,ip地址的表示方式点分十进制加子网掩码,让你求出与给出的网络号没有重复网段并且所有网络号合并可以组成整个网络同时保证你列举 出来的网络数量最少,将网络地址输出。

这道题目模型是一棵树,问题可以抽象成询问需要加多少个节点使得树的每一个父亲都有两个儿子。

树的表示方法深度表示的ip中的第几位,一个节点遇到0到左儿子遇到1到右儿子,这样每个ip地址都可以用树上的一条路径表示出来,深蓝色的点表示根,黄色点表示遍历过的点,深蓝色表示的终止节点,红色表示是要添加的点对应的路径转化后就是最后要输出的答案。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
#include<stdlib.h>
using namespace std;
#define INF 0x80000000
#define Nim 0xff
int T;
int tt = 1;
bool ok;
struct node{
    unsigned int ip;
    int net;
    node(unsigned int t = 0,int s = 0){
        ip = t;net = s;
    }
};
map<long long int,bool>b;
map<long long int,bool>fk;
node t;
vector<node> v;
void insert(long long int rt,int k){
    b[rt] = 1;
    if(k>=t.net){fk[rt]=1;return;}
    int now = (t.ip&(INF>>k))>>(31-k);
    if(now==0)insert(rt<<1,k+1);
    if(now==1)insert(rt<<1|1,k+1);
}
unsigned int st;
void print(node now){
    int l[4];unsigned int tem = now.ip;
    for(int i=0;i<4;i++){
        l[i] = tem&Nim;
        tem>>=8;
    }
    printf("%d",l[3]);
    for(int i=2;i>=0;i--){
        printf(".%d",l[i]);
    }
    printf("/%d\n",now.net);
}
void output(){
    printf("Case #%d:\n",tt++);
    if(v.size()==0){printf("0\n");return;}
    else{
        printf("%d\n",v.size());
        for(int i=0;i<v.size();i++){
            print(v[i]);
        }
    }
}
void dfs(long long int rt,int k){
    //cout<<rt<<" "<<v.size()<<endl;system("PAUSE");
    if(fk[rt])return;
    if(b[rt]==0){
        if(rt%2==0){
            if(b[rt|1]){
                v.push_back(node(st,k));
            }
        }else{
            if(b[rt-1]){
                v.push_back(node(st,k));
            }
        }
        return;
    }
    unsigned int tem = st;
    dfs(rt<<1,k+1);
    st = tem|(INF>>k);
    dfs(rt<<1|1,k+1);
    st = tem;
}
void test(){
    for(int i=0;i<10;i++){
        cout<<fk[i]<<" ";
    }cout<<endl;
    for(int i=0;i<10;i++){
        cout<<b[i]<<" ";
    }cout<<endl;
}
int main(){
    scanf("%d",&T);
    while(T--){
        ok = 0;
        v.clear();
        int num;b.clear();fk.clear();
        scanf("%d",&num);if(num==0){printf("Case #%d:\n",tt++);printf("1\n");printf("0.0.0.0/0\n");continue;}
        for(int i=0;i<num;i++){
            int a;char b;
            unsigned tem  =0;
            for(int j=0;j<4;j++){
                scanf("%d%c",&a,&b);
                tem<<=8;
                tem+=a;
            }
            //cout<<tem<<endl;
            t.ip = tem;scanf("%d",&t.net);
            if(t.net==0)ok = 1;
            insert(1,0);
        }
        st = 0;
        dfs(1,0);// test();
        output();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值