1. 程式人生 > >優雅競賽之 UVa 1590 IP Networks

優雅競賽之 UVa 1590 IP Networks

IP網路 UVa 1590

來自 演算法入門 競賽經典 第二版 第四章
習題4-5

最初以為該題比較簡單,真正開始寫才遇到許多問題。

問題:

  • 位操作不直觀,思考了一會
  • 右移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; }

最後附上一段網上的實現

#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;
}

評價:使用了大量陣列操作,雖然使用位操作,但沒有掌握其核心。可讀性極差,邏輯不清晰,過程複雜。使用合理位操作可以大量簡化程式碼。