洛谷 P2815 IPv6地址壓縮 題解

P2815 IPv6地址壓縮

題目背景

(友情提示:IPv6基礎知識曾屢次出如今NOIP初賽中)Internet Protocol,互聯網協議,即爲咱們常說的IP。咱們目前常說的IP主要指它的第四版,即IPv4,它由IETF於1981年發佈。它的地址長度是32個二進制位,所以也就有2^32個IP地址可供使用,約爲43億,在當時,誰也沒有料想到IPv4如此龐大的地址長度會有用完的一天。linux

在21世紀的今天,互聯網的蓬勃發展早就了咱們現在便利的生活。當下,世界人口已超過70億,計算機和各類聯網設備已經走入千家萬戶,而再也不僅是上個世紀80年代科學家們的工具。此時便出現了人們日益增加的聯網設備須要同落後IPv4地址長度之間的矛盾。儘管能夠經過網絡地址翻譯能技術來共享IP地址,臨時解決枯竭的問題,但顯然不是長久之計。ios

IETF也有先見之明,早早地於1998年發佈了IPv6協議,從微軟2006年發佈的Windows Vista開始成爲默認安裝的網絡協議。做爲IPv4的繼任者,它的地址長度爲128個二進制位,也就是2^128個IP地址可供使用。然而面對這冗長的地址,一位記憶力很差的網絡工程師小明在配置路由表時遇到了許許多多多的困難,如今他找到了你,但願你幫忙編寫一個程序來按照IPv6地址標準的格式壓縮規則來壓縮IPv6地址。macos

題目描述

IPv6格式

IPv6二進位制下爲128位長度,以16位爲一組,每組以冒號「:」隔開,能夠分爲8組,每組以4位十六進制方式表示。windows

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

同時IPv6地址在某些條件下能夠壓縮:

①每組數字表明的獨立16進制數能夠省略前位的0。

例如上面的IPv6地址可被壓縮爲:工具

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

②能夠用雙冒號「::」表示一組0或多組連續的0,但只能出現一次

例如上面的IPv6地址可被壓縮爲:翻譯

2001:db8::123:4567:89ab:cdefcode

請你幫助記憶力很差的網絡工程師小明解決他遇到的問題。ip

規則補充:

①輸入數據爲徹底展開的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地址

輸入輸出樣例

輸入 #1

240e:0014:6000:0000:0000:0000:0000:0001

輸出 #1

240e:14:6000::1

輸入 #2

2001:0db8:0000:0000:0000:0000:0000:0001

輸出 #2

2001:db8::1

輸入 #3

2001:4860:4860:0000:0000:0000:0000:8888

輸出 #3

2001:4860:4860::8888

輸入 #4

2400:8900:e000:0010:0000:0000:0000:0000

輸出 #4

2400:8900:e000:10::

輸入 #5

0000:0000:0000:0000:0000:0000:0000:0000

輸出 #5

::

輸入 #6

0000:0000:0000:0000:0000:0000:0000:0001

輸出 #6

::1

輸入 #7

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

輸出 #7

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

輸入 #8

1234:5678:9abc:def0🔢5678:9abc:def0

輸出 #8

1234:5678:9abc:def0🔢5678:9abc:def0

輸入 #9

0001:0000:0000:0000:0000:0000:0000:0001

輸出 #9

1::1

輸入 #10

0000:0000:0000:0000:0000:0000:0001:0002

輸出 #10

::1:2

【思路】

模擬

【題目大意】

將完整的的IPv6的顯示方式壓縮爲macOS(Darwin)默認的IPv6地址顯示方式

【題目分析】

壓縮方式即爲:
將每一組數 (每一組數是沒有被:隔開的連續的4個數)的前導0去掉
不過若是是0000那就只能壓縮爲0
將最長的連續的0000這樣的串能夠壓縮爲::
好比0000:0000:0000:0000就能夠壓縮爲::
若是有兩個相同長度的那就替換前面的

【核心思路】

先找出最長的連續0000串第一個數的位置
到時輸出輸出完成::以後直接跳到這個串的最後一位就行了
總的來講上面這個仍是比較好處理的
去除前導0纔是最難的
這個時候就會有人說了,這不就是一個while循環搞的定的嘛,哪裏難了
這個時候很容易會Wa掉第一個點
本人就出在這個問題上面
由於通常用while循環判斷是否是這組數的最後一個通常會用下一個是否是:來判斷
可是!
想沒想過最後一組數的最後一位怎麼判斷?這個後面可沒有:
很容易被忽略的哦
可是知道問題所在以後稍微特判一下就能夠了

【提供一組小數據】

關於第一個點錯誤的樣例
abcd:0000:0000🔡0012:0000:0001:0000
正解: abcd:🔡12:0:1:0
錯解: abcd:🔡12:0:1:

【完整代碼】

#include<iostream>
#include<cstdio>
#include<cstring>.
#include<string>

using namespace std;
string s;
int main()
{
    cin >> s;
    int l = s.length();
    int a = 0;
    int js = 0;//記錄目前0串的長度 
    int M = 0;//記錄最大的幾組0的長度 
    int wz = -1;//最長0那一串中第一個0的位置 
    int last = -1;//上一個0串的位置 
    for(register int i = 0;i < l;i += 5)
    {
        if(s[i] == '0' && s[i + 1] == '0' && s[i + 2] == '0' && s[i + 3] == '0')//一組完整的0 
        {
            if(last == i - 5)
            {
                last = i;
            }
            else
            {
                js = 0;
                last = i;
                a = i;
            }
            js ++;
        }
        if(js > M)
        {
            M = js;
            wz = a;
        }
    }
    int jj = 0;
    while(jj < l)
    {
        if(jj == wz)
        {
            if(jj == 0)
                cout << ":";
            jj += M * 5 - 1;
            if(jj == l)
                cout << ":";
        }
        else
        {
            if(jj % 5 == 0)
            {
                if(jj >= 35)//若是是最後一組的話,那就不能根據下一個是否是:來判斷這個0是否是這組數中最後一個數了 
                {
                    while(s[jj] == '0' && jj + 1 != l)
                    {
                        jj ++;
                    }
                }
                else
                {
                    while(s[jj] == '0' && s[jj + 1] != ':')
                    {
                        jj ++;
                    }
                }
            }
            cout << s[jj]; 
            jj ++;
        }
    }
    cout << endl;
    return 0;
}
/*
2001:0db8:0000:0000:0123:4567:89ab:cdef
012345678901234567890123456789012345678

abcd:0000:0000:abcd:0012:0000:0001:0000
*/
相關文章
相關標籤/搜索