优雅竞赛之 UVa 1590 IP Networks

本文介绍了一种解决UVa1590 IP网络问题的有效方法,通过将IP地址转换为整数进行位操作,避免了复杂的数组处理,实现了简洁高效的代码。

IP网络 UVa 1590

来自 算法入门 竞赛经典 第二版 第四章
习题4-5

UVa原题链接

最初以为该题比较简单,真正开始写才遇到许多问题。

问题:

  • 位操作不直观,思考了一会
  • 右移32位与没有位移相同

优雅之处:

  • 简单易懂的位操作
  • 简单化的解题方法
  • 没有使用数组
  • 代码逻辑清晰

关键之处:

将ip地址转成整数,即可方便直接位操作运算,而不用使用大量数组同时跨数组计算,使代码臃肿,可读性低。

具体实现代码如下

#include <iostream>
#include <cstring>
#include <string>
#include <sstream>

using namespace std;

string int_to_ip(int i) {

    stringstream ss;
    string ip;

    int i1 = (i >> 24) & 0xff;
    int i2 = (i >> 16) & 0xff;
    int i3 = (i >> 8) & 0xff;
    int i4 = (i >> 0) & 0xff;

    ss << i1 << '.' << i2 << '.' << i3 << '.' << i4;
    ss >> ip;

    return ip;
}

int ip_to_int(string ip) {

    stringstream in(ip);
    int r = 0;

    for (int i = 0; i < 4; i++) {

        string part;
        getline(in, part, '.');

        int v = atoi(part.c_str()) & 0xff;

        r |= v << (3 - i) * 8;
    }

    return r;
}

int main() {

    int n;

    while (cin >> n) {

        unsigned int ip_min = 0xffffffff;
        unsigned int ip_max = 0x00000000;

        for (int i = 0; i < n; i++) {
            string str;
            cin >> str;
            unsigned int ip = ip_to_int(str) & 0xffffffff;

            if (ip > ip_max) {
                ip_max = ip;
            }

            if (ip < ip_min) {
                ip_min = ip;
            }
        }

        int bits = 32;
        for (; bits > 0; bits--) {
            if (ip_min >> (bits - 1) != ip_max >> (bits - 1)) {
                //找到最高不同位,从此为开始将掩码和最小ip往后全置0即可
                break;
            }
        }

        unsigned int mask = 0b11111111111111111111111111111111;

        for (int i = 0; i < bits; i++) {
            //将末尾位全部置0
            mask &= ~(1 << i);
            ip_min &= ~(1 << i);
        }

        cout << int_to_ip(ip_min) << endl;
        cout << int_to_ip(mask) << endl;
    }

    return 0;
}

最后附上一段网上的实现

[刷题]算法竞赛入门经典(第2版) 4-5/UVa1590 - IP Networks

#include<iostream>
unsigned i, m, num, ip[4], ipmax[4], ipmin[4], mask[4];
int cmp(unsigned *a, unsigned *b) {//compare
    for (int i = 0;i < 4;++i) {
        if (a[i] < b[i]) return -1;
        if (a[i] > b[i]) return 1;
    }
    return 0;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while (scanf("%d", &m) != -1) {
        scanf("%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
        for (i = 0;i < 4;++i) ipmax[i] = ipmin[i] = ip[i];
        while (--m) {
            scanf("%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
            if (cmp(ip, ipmax) == 1)
                for (i = 0;i < 4;++i) ipmax[i] = ip[i];
            else if (cmp(ip, ipmin) == -1)
                for (i = 0;i < 4;++i) ipmin[i] = ip[i];
        }
        for (i = 0;i < 4;++i) {
            if (i == 0 || mask[i - 1] == 255) {
                mask[i] = 255 ^ (ipmax[i] ^ ipmin[i]);
                for (int j = 0;j <= 8;++j)
                    if ((mask[i] >> j) == (255 >> j)) {
                        mask[i] = ((mask[i] >> j) << j);
                        break;
                    }
            }
            else mask[i] = 0;
        }
        printf("%u.%u.%u.%u\n", mask[0] & ipmax[0], mask[1] & ipmax[1], mask[2] & ipmax[2], mask[3] & ipmax[3]);
        printf("%u.%u.%u.%u\n", mask[0], mask[1], mask[2], mask[3]);
    }
    return 0;
}

评价:使用了大量数组操作,虽然使用位操作,但没有掌握其核心。可读性极差,逻辑不清晰,过程复杂。使用合理位操作可以大量简化代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值