1. 程式人生 > 實用技巧 >洛谷P2815 IPv6地址壓縮

洛谷P2815 IPv6地址壓縮

題目描述

IPv6格式

IPv6二進位制下為128位長度,以16位為一組,每組以冒號“:”隔開,可以分為8組,每組以4位十六進位制方式表示。

例如:2001:0db8:0000:0000:0123:4567:89ab:cdef 是一個合法的IPv6地址。

同時IPv6地址在某些條件下可以壓縮:

每組數字代表的獨立16進位制數可以省略前位的0。
例如上面的IPv6地址可被壓縮為:

2001:db8:0:0:123:4567:89ab:cdef

可以用雙冒號“::”表示一組0或多組連續的0,但只能出現一次
例如上面的IPv6地址可被壓縮為:

2001:db8::123:4567:89ab:cdef

請你幫助記憶力不好的網路工程師小明解決他遇到的問題。

規則補充:

輸入資料為完全展開的IPv6地址,確保輸入的IPv6地址不含雙冒號,每組地址省略的0都會被補充上去。

雙冒號只能使用一次,因此我們壓縮最長的全0組

比如:2001:0db8:0000:0000:1:0000:0000:0000

我們壓縮為2001:db8:0:0:1::,而非2001:db8::1:0:0:0

雙冒號只能只用一次,因此我們在我們遇到地址中多個連續全0組長度相同時,我們壓縮最前面的一個。
2001:0db8:0000:0000:ffff:0000:0000:1

壓縮為2001:db8::ffff:0:0:1,而非2001:db8:0:0:ffff::1

輸入的IPv6地址可能無法被壓縮,因此請照原樣輸出。
提示:本題所示的壓縮規則與macOS(Darwin)預設的IPv6地址顯示方式相同,而Windows和Linux只遇到一組全0時不會使用::進行壓縮。但用此方法壓縮過的IPv6地址一樣可以被Windows和Linux正確識別。

例如:2001:0db8:ffff:0000:0123:4567:89ab:cdef

Darwin壓縮為:2001:db8:ffff::123:4567:89ab:cdef

Linux、Windows壓縮為:2001:db8:ffff:0:123:4567:89ab:cdef

輸入格式

一串39個字元的字串,代表一個完全展開的IPv6地址

輸出格式

一串壓縮後的IPv6地址

輸入輸出樣例

輸入:240e:0014:6000:0000:0000:0000:0000:0001
輸出:240e:14:6000::1

AC程式碼

#include <bits/stdc++.h>

using namespace std;
string addr_full;
string sections[8];
int section_isZero[8] = {};
struct ommit_section {
    int len, start, end;
};
/* 0 start */
string get_section(int i) {
    int start;
    start = i * 5;
    return addr_full.substr(start, 4);
}

string edit_section(int i) {
    section_isZero[i] = (sections[i][0] == '0' && sections[i][1] == '0' &&
                         sections[i][2] == '0' && sections[i][3] == '0');
    if (section_isZero[i]) {
        sections[i] = "0";
        return sections[i];
    }
    //先看這段是不是全0
    string tmp;
    int flag = 0;
    for (int j = 0; j <= 3; j++) {
        if (sections[i][j] != '0') {
            flag = j;
            break;
        }
    }
    tmp = sections[i].substr(flag, 4 - flag);
    sections[i] = tmp;
    return tmp;
}

int main() {
    cin >> addr_full;
    /* 一個IPV6地址最多分8段 */
    for (int i = 0; i < 8; i++) {
        sections[i] = get_section(i);
        edit_section(i);
    }
    vector<struct ommit_section> os;
    for (int i = 0; i < 8; i++) {
        if (section_isZero[i] == 1) {
            int cnt = 1, start = i, end;
            for (int j = i + 1; j <= 8; j++) {
                if (section_isZero[j] == 0 || j == 8) {
                    end = j - 1;
                    struct ommit_section tmp = {cnt, start, end};
                    os.push_back(tmp);
                    i = j;
                    break;
                } else
                    cnt++;
            }
        }
    }
    int max_len = 0, start = -1, end = 8;
    for (int i = 0; i < os.size(); i++) {
        if (max_len < os[i].len) {
            max_len = os[i].len;
            start = os[i].start;
            end = os[i].end;
        }
    }
    if (start >= 0 && end <= 7) {
        for (int i = 0; i < start; i++) {
            cout << sections[i] << ":";
        }
        if (start == 0)
            cout << ":";
        cout << ":";
        for (int i = end + 1; i < 8; i++) {
            cout << sections[i];
            if (i != 7)
                cout << ":";
        }
    } else {
        for (int i = 0; i < 7; i++) {
            cout << sections[i] << ":";
        }
        cout << sections[7];
    }
}

沒有演算法,暴力模擬就完事了