UVALive 7043 International Collegiate Routing Contest 字典树,递归

本文介绍了一种解决IPv4子网地址划分问题的算法,通过使用字典树(Trie树)存储并查找未被分配的子网地址,确保所求子网与已知子网不重叠且构成完整网络。

题目链接:这里
题意:给出n个IPv4的子网地址,格式是a-b-c-d/l,a b c d l都是十进制数,然后l是网络地址的长度,最长到32,要求输出最低限度的所有的未能划分出的子网地址,这些子网和给出的n个子网没有交集,这些地址和给出的n个地址能组成完整的网络地址。
解法:把所有的ip地址插进字典树,并且标记单词节点,之后然后暴力递归找所有未被包含在已有子网里的子网地址。其实就是trie树上暴力。。。。不过题意看pdf看了超久,还是在网上的解题报告弄清题意的,读题需要训练了。

//LA 7043

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000010;

struct Trie{
    struct node{
        int a, b, c, d, l;
        node(){}
        node(int a, int b, int c, int d, int l) : a(a), b(b), c(c), d(d), l(l) {}
    };
    int n, cnt, ans[40];
    char s[40];
    vector <node> v;
    int root, sz, ch[maxn][2], flag[maxn];
    void get(int x){
        for(int i = 7; i >= 0; i--){
            if((x>>i)&1) s[cnt++] = '1';
            else s[cnt++] = '0';
        }
    }
    void init(){
        root = 0;
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
        v.clear();
    }
    void insert(char *s, int len){
        int u = root;
        for(int i = 0; i < len; i++){
            int now = s[i] - '0';
            if(!ch[u][now]){
                memset(ch[sz], 0, sizeof(ch[sz]));
                flag[sz] = 0;
                ch[u][now] = sz++;
            }
            u = ch[u][now];
        }
        flag[u] = 1;
    }
    void query(int u, int cur){
        if(flag[u]) return;
        for(int j = 1; j >= 0; j--){
            ans[cur] = j;
            if(ch[u][j]){
                query(ch[u][j], cur+1);
            }
            else{
                int a, b, c, d;
                int tt, l, r;
                tt = 0, l = 0, r = 7;
                for(int i = l; i <= r; i++) tt = tt * 2 + ans[i];
                a = tt;
                tt = 0, l = 8, r = 15;
                for(int i = l; i <= r; i++) tt = tt * 2 + ans[i];
                b = tt;
                tt = 0, l = 16, r = 23;
                for(int i = l; i <= r; i++) tt = tt * 2 + ans[i];
                c = tt;
                tt = 0, l = 24, r = 31;
                for(int i = l; i <= r; i++) tt = tt * 2 + ans[i];
                d = tt;
                v.push_back(node(a, b, c, d, cur));
            }
        }
    }
    void run(){
        int T, ks = 0;
        scanf("%d", &T);
        while(T--){
            init();
            scanf("%d", &n);
            printf("Case #%d:\n", ++ks);
            if(n == 0){
                printf("1\n");
                printf("0.0.0.0/0\n");
            }
            else{
                for(int i = 0; i < n; i++){
                    int a, b, c, d, l;
                    scanf("%d.%d.%d.%d/%d", &a, &b, &c, &d, &l);
                    cnt = 0;
                    get(a), get(b), get(c), get(d);
                    s[cnt] = 0;
                    insert(s, l);
                }
                query(0, 0);
                cout << v.size() << endl;
                for(int i = 0; i < (int)v.size(); i++){
                    printf("%d.%d.%d.%d/%d\n", v[i].a, v[i].b, v[i].c, v[i].d, v[i].l + 1);
                }
            }
        }
    }
}ac;
int main()
{
    ac.run();
    return 0;
}
<think> 我们分析用户提供的代码,并解释为什么输入"International Collegiate Programming Contest"后,变量k的值是13。 代码: #include <iostream> using namespace std; int main() { string a; cin >> a; int k = a.size(); cout << k; cout << a[0]; for(int i=0; i<k-1; i++) { if(a[i]==32) cout << a[i+1]; } } 注意:cin使用>>运算符读取字符串时,会在遇到空白字符(空格、制表符、换行符等)时停止读取。因此,当输入为"International Collegiate Programming Contest"(包含空格)时,cin>>a只会读取第一个单词"International",而忽略空格后面的内容。 所以,变量a的值是"International",其长度(a.size())为13(因为"International"由13个字母组成)。因此,k被赋值为13。 后续代码: 1. 输出k(即13)。 2. 输出a[0](即'I')。 3. 然后循环遍历字符串a(即"International")的每个字符(从索引0到11,因为k-1=12,循环条件为i<12,即i从0到11),检查当前字符是否为空格(ASCII码32)。由于a中不包含空格(因为只读取了第一个单词),所以循环内不会输出任何内容。 因此,程序输出为:13I 总结:k的值为13是因为cin>>a只读取了输入的第一个单词"International",其长度为13。 为了验证,我们可以考虑如果希望读取整行(包括空格),应该使用getline(cin, a)。 生成相关问题: 1. 如何修改代码才能读取整行输入? 2. cin和getline在读取字符串时有什么区别? 3. 为什么在输入包含空格的字符串时,cin只读取第一个单词? 4. 如果希望输出每个单词的首字母(即输出"ICPC"),应该如何修改代码? </think> 根据提供的代码和输入分析,变量 `k` 的值为 **13** 的原因如下: ### 关键原因分析 1. **`cin` 的输入特性** 当使用 `cin >> a` 读取输入时,`cin` 会在遇到**第一个空白字符(空格、制表符等)** 时停止读取。输入 `'International Collegiate Programming Contest'` 包含空格,因此 `cin` 只会读取第一个单词 `"International"` 并存入字符串 `a` 中[^1][^3]。 2. **字符串长度计算** `"International"` 的字符数为 **13**(可通过逐个字母计数验证:`I-n-t-e-r-n-a-t-i-o-n-a-l`),因此 `k = a.size()` 的结果为 `13`[^3]。 3. **代码输出验证** - `cout << k` 输出 `13` - `cout << a[0]` 输出首字母 `I` - 后续循环检查空格并输出下一字母,但 `a` 中无空格(仅含 `"International"`),故无额外输出。 最终输出为 `13I`。 ### 完整执行流程 ```cpp #include <iostream> using namespace std; int main() { string a; // 定义字符串a cin >> a; // 只读取"International"(空格前内容) int k = a.size(); // k = 13("International"的长度) cout << k; // 输出13 cout << a[0]; // 输出'I' for (int i = 0; i < k - 1; i++) { // 遍历字符串 if (a[i] == 32) // 32是空格的ASCII码 cout << a[i + 1]; // 因无空格,此处无输出 } } ``` ### 修正建议 若需读取含空格的完整输入,应使用 `getline()`: ```cpp getline(cin, a); // 读取整行(包含空格) ``` ### 相关问题 1. 为什么 `cin` 遇到空格会停止读取?如何避免? 2. C++ 中 `string::size()` 的计算规则是什么? 3. 如何正确输出输入字符串中每个单词的首字母(例如输出 `"ICPC"`)? [^1]: `cin` 在遇到空格时停止读取输入。 [^3]: 字符串长度由实际存储内容决定。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值