UVALive 7043 字典树+DFS

题意

分配子网,给一个子网地址,求出除了这个子网地址以外的所有子网地址。

题解

裸的字典树。只不过在子网地址记录上有一些技巧,因为子网地址恰好可以用32位整数表示,所以可以用一个unsigned int 进行状态压缩,这样就不用去搞字符串进行记录了。ORZ。。
至于寻找子网地址,在字典树上进行DFS,如果某个节点的子节点都不存在(比如说字典树为空的情况),那么就记录这个节点的状态。如果某个节点的某个子节点不存在,那么就记录这个子节点的状态。在函数开始的时候对已经存在的状态进行过滤判断,如果当前访问的子网节点是已经分配的子网节点,直接return就可以了。

代码

#include<bits/stdc++.h>
#define Ll long long
const int mod =1000000007;
#define UP(i,a,b) for(int i=a;i<b;i++)
#define DOWN(i,b,a) for(int i=b-1;i>=a;i--)
#define MEM(a,b) memset(a,b,sizeof(a))
#define W(i) while(i)
#define UINT unsigned int
using namespace std;

int ch[1100000][2],val[1100000];
int num[32];
int sz,len;
int anspos;
UINT ans[1100000],anslen[1100000];

void insert()

{
    int u=0;
    UP(i,0,len) {
        int x=num[i];
        if(!ch[u][x]) {
            ch[u][x]=sz++;
        }
        u=ch[u][x];
    }
    val[u]=1;
}

void dfs(int u,UINT num,int deep) {
    if(val[u]) {
        return ;
    }
    if(!ch[u][0]&&!ch[u][1]) {
        ans[anspos]=num;
        anslen[anspos++]=deep;
//        cout<<deep<<endl;
        return ;
    }
    if(ch[u][0]) {
        dfs(ch[u][0],num,deep+1);
    } else {
        ans[anspos]=num;
        anslen[anspos++]=deep+1;
    }
    if(ch[u][1]) {
        dfs(ch[u][1],num|(1U<<(31-deep)),deep+1);
    } else {
        ans[anspos]=num|(1U<<(31-deep));
        anslen[anspos++]=deep+1;
    }
}

int main()

{
    int t;
    scanf("%d",&t);
    int ks=1;
    W(t--)
    {
        MEM(ch,0);
        MEM(val,0);
        MEM(ans,0);
        MEM(anslen,0);
        sz=1;
        anspos=0;
        int n;
        scanf("%d",&n);
        UP(i,0,n) {
            int x;
            UP(j,1,5) {
                scanf("%d%*c",&x);
                UP(k,1,9) {
                    num[j*8-k]=x%2;
//                    cout<<x%2<<" "<<(j*8-k)<<endl;
                    x/=2;
                }
            }
            scanf("%d",&len);
            insert();
        }
//        cout<<ch[0][0]<<" "<<ch[0][1]<<endl;
        dfs(0,0,0);
        printf("Case #%d:\n",ks++);
        printf("%d\n",anspos);
        UP(i,0,anspos){
            int a[4];
            DOWN(j,4,0){
                a[j]=ans[i]&((1<<8)-1);
                ans[i]=ans[i]>>8;
            }
            UP(i,0,4){
                 if(i==3){
                    printf("%u/",a[i]);
                }else{
                    printf("%u.",a[i]);
                }
            }
            printf("%u\n",anslen[i]);
        }
    }
}

/*
5
1
255.255.255.128/25
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值