(友情提示: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二進位制下爲128位長度,以16位爲一組,每組以冒號「:」隔開,能夠分爲8組,每組以4位十六進制方式表示。windows
例如:2001:0db8:0000:0000:0123:4567:89ab:cdef 是一個合法的IPv6地址。網絡
例如上面的IPv6地址可被壓縮爲:工具
2001:db8:0:0:123:4567:89ab:cdefspa
例如上面的IPv6地址可被壓縮爲:翻譯
2001:db8::123:4567:89ab:cdefcode
請你幫助記憶力很差的網絡工程師小明解決他遇到的問題。ip
好比:2001:0db8:0000:0000:1:0000:0000:0000
咱們壓縮爲2001:db8:0:0:1::,而非2001:db8::1:0:0:0
2001:0db8:0000:0000:ffff:0000:0000:1
壓縮爲2001:db8::ffff:0:0:1,而非2001:db8:0:0:ffff::1
例如: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 */