문제 출처 : https://www.acmicpc.net/problem/3107
문제
IPv6은 길이가 128비트인 차세대 인터넷 프로토콜이다.
IPv6의 주소는 32자리의 16진수를 4자리씩 끊어 나타낸다. 이때, 각 그룹은 콜론 (:)으로 구분해서 나타낸다.
예를 들면, 다음과 같다.
2001:0db8:85a3:0000:0000:8a2e:0370:7334
32자리의 16진수는 사람이 읽고 쓰기에 불편하고, 대부분의 자리가 0이기 때문에 아래와 같이 축약할 수 있다.
- 각 그룹의 앞자리의 0의 전체 또는 일부를 생략 할 수 있다. 위의 IPv6을 축약하면, 다음과 같다
2001:db8:85a3:0:00:8a2e:370:7334
- 만약 0으로만 이루어져 있는 그룹이 있을 경우 그 중 한 개 이상 연속된 그룹을 하나 골라 콜론 2개(::)로 바꿀 수 있다.
2001:db8:85a3::8a2e:370:7334
2번째 규칙은 모호함을 방지하기 위해서 오직 한 번만 사용할 수 있다.
올바른 축약형 IPv6주소가 주어졌을 때, 이를 원래 IPv6 (32자리의 16진수)로 복원하는 프로그램을 작성하시오.
입력
첫째 줄에 올바른 IPv6 주소가 주어진다. 이 주소는 최대 39글자이다. 또한, 주소는 숫자 0-9, 알파벳 소문자 a-f, 콜론 :으로만 이루어져 있다.
출력
첫째 줄에, 입력으로 주어진 IPv6의 축약되지 않은 형태를 출력한다.
알고리즘 분류
풀이
우선 ::같이 연속으로 나온 경우를 풀기 위해
':'의 개수 partCnt를 구한다.
::3같은 경우 partCnt는 2이고,
0000:0000:0000:0000:0000:0000:0000:0003 과 같이 되어야 한다.
본인은 전체 32개의 비트에서 4개의 비트씩 끊어서 총 4개의 비트가 8개가 있기 때문에
기준을 8로 잡았는데, :의 전체 수인 7로 해도 무관하다.
위의 경우는 0000을 7번 추가해야 한다. 기준을 8이라고 할 때, :의 개수는 2개, 즉 8-2+1 번 만큼 0000을 추가하면 된다.
3::의 경우도 partCnt는 2이다.
이 경우도 0000을 7번 추가해야 하고, 기준을 8이라고 할 때, 8-2+1번 만큼 0000을 추가하면 된다.
3::2의 경우는 어떨까?
0003:0000:0000:0000:0000:0000:0000:0002 과 같이 나와야 하기 때문에
0000은 6번 나와야 한다.
partCnt는 2이고, 8-2는 6이다.
즉 ::가 3::2 , 1:3:2::5와 같이 숫자 사이에 껴있는 경우는 8-partCnt,
::3, 1::와 같이 맨 끝에 ::가 위치하는 경우는 8-partCnt+1번 만큼 0000을 추가하면 된다.
23 -> 0023
abb -> 0abb
등을 구현하는 것은 문자열의 인덱스를 뒤에서부터 검사하며, 반복문 중에 : 를 만나기 전까지는 결과 문자열에 문자 그대로 추가하고 문자 수를 센다.
:를 만난다면 (4-문자 수)만큼 0을 추가하면 된다.
코드(Kotlin)
import java.io.InputStreamReader
import java.io.BufferedReader
fun main() = with(System.out.bufferedWriter()){
val br = BufferedReader(InputStreamReader(System.`in`))
val input = br.readLine()
var answer=""
var partCnt=0
for(i in input.indices){
if(input[i]==':'){
partCnt++;
}
}
var len=0
var skip=false
for(i in input.length-1 downTo 0){
if(skip==true){
skip=false
continue
}
if(input[i]==':'){
while(len++<4){
answer = '0'+answer
}
if(i-1>=0 && input[i-1]==':'){
var cnt = 8-partCnt
if( i-1==0){
cnt++
}
while(cnt--!=0){
answer = "0000" +answer
}
skip=true
len=0
continue
}
len=0
}
else{
answer=input[i] +answer
len++
}
}
if(len!=0){
while(len++<4){
answer = '0'+answer
}
}
var idx=3
for(i in answer.indices){
write("${answer[i]}")
if(i==idx && i!=answer.length-1){
write(":")
idx+=4
}
}
close()
}
코드(c++)
#include <iostream>
#include <string>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
string input;
cin >> input;
string answer = "";
//int idx=
int partCnt = 0;
for (int i = 0; i < input.length(); i++) {
if (input[i] == ':') {
partCnt++;
}
}
int len = 0;
for (int i = input.length() - 1; i >= 0; i--) {
if (input[i] == ':') {
while (len < 4) {
answer = '0' + answer;
len++;
}
if (i - 1 >= 0 && input[i - 1] == ':') {
len = 0;
int cnt = 8 - partCnt;
if (i - 1 == 0) {
cnt++;
}
while (cnt--) {
answer = "0000" + answer;
}
i--;
continue;
}
len = 0;
}
else {
len++;
answer = input[i] + answer;
}
}
if (len > 0) {
while (len < 4) {
answer = '0' + answer;
len++;
}
}
int idx = 3;
for (int i = 0; i < answer.length(); i++) {
cout << answer[i];
if (i == idx && idx!=answer.length()-1) {
cout << ':';
idx += 4;
}
}
return 0;
}
'알고리즘 문제 풀이 > 백준' 카테고리의 다른 글
백준 3151 합이 0 Kotlin (투 포인터) (3) | 2021.11.19 |
---|---|
백준 16637 괄호 추가하기 Kotlin (완전탐색) (0) | 2021.11.18 |
백준 1548 부분 삼각 수열 c++ (완전탐색) (0) | 2021.11.16 |
백준 16926 배열 돌리기 1 c++ (구현) (0) | 2021.11.15 |
백준 2224 명제 증명 c++ (플로이드 와샬) (0) | 2021.11.14 |
댓글