习题4-5 UVA1590 IP Networks(37行AC代码)

本文提供了一种解决UVA1590 IPNetworks问题的方法,通过找出给定IP地址集合的最大和最小值,计算二进制表示下的最长公共前缀,以此确定包含所有IP的最小IP网络。使用C++11、bitset和位运算实现AC代码。

紫书刷题进行中,题解系列点这里

习题4-5 UVA1590 IP Networks(37行AC代码)

题目大意

给定若干个IP地址,求包含所有IP的最小IP网络。

  • IP地址:4个字节,每个字节用十进制表示,并用点分割,形如xxx.xxx.xxx.xxx,无前导0,每个十进制在[0,255]
  • IP网络:由子网地址和子网掩码构成,二者形式和IP地址一样,二者存在制约关系,假设有n(处于[0,32]),那么在二者的二进制表示中
    • 子网掩码的前n位为1,后32-n位为0
    • 子网地址的前n位任意,后32-n位为0
  • 假设n=24,子网地址假设为198.123.123.0,子网掩码255.255.255.0,那么198.123.123.0~198.123.123.255均属于该IP网络

思路分析

可先找出所有IP地址中最大和最小值,再计算最大小值的二进制形式的最长公共子串长度len(从头开始),接着将最小值二进制低32-n置0,构造前n位为1,后32-n位为0的子网掩码。

  • 比较大小:可用stringstream分割IP地址,并计算出32位的数字,从而得到最大和最小值
  • 位处理:可用bitset完成二进制字符串和数值间相互转化,每个位的0/1设置

AC代码(C++11,bitset,位运算)

#include<bits/stdc++.h>
using namespace std;
void binstrToIP(string s) { // 二进制字符串转为IP形式
    for (int i = 0; i < 4; i ++) {
        bitset<8> bt(s.substr(i*8,8));
        printf("%u%s", bt.to_ulong(), i == 3 ? "\n" : ".");
    }
}
int main() {
    int n;
    while (cin >>n) {
        string smax, smin, smask, s, st;
        unsigned umin=UINT32_MAX, umax = 0;
        while (n --) {
            cin >>s;
            stringstream input(s);
            unsigned uint = 0;
            while (getline(input, st, '.')) { // 分割每个部分
                uint = (uint << 8) + (unsigned)stoi(st); // 256进制
            }
            if (umin >= uint) umin = uint, smin = s; // 最小值
            if (umax <= uint) umax = uint, smax = s; // 最大值
        }
        bitset<32> bmin(umin), bmax(umax), bmask(0xffffffffu);
        smin = bmin.to_string(); smax = bmax.to_string(); // 转为2进制字符串
        int cnt = 0;
        for (int i = 0; i < 32; i ++) { // 统计从头开始的公共子串长度
            if (smin[i] == smax[i]) cnt ++;
            else break;
        }
        for (int i = 0; i < 32-cnt; i ++) { // 设置IP地址和掩码低32-cnt位为0
            bmin.reset(i); bmask.reset(i); // 注意bitset逆序存储
        }
        binstrToIP(bmin.to_string()); binstrToIP(bmask.to_string());
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值