본문 바로가기
알고리즘 문제 풀이/백준

백준 3107 IPv6 c++,Kotlin (구현,문자열)

by 옹구스투스 2021. 11. 17.
반응형

문제 출처 : https://www.acmicpc.net/problem/3107

 

3107번: IPv6

첫째 줄에 올바른 IPv6 주소가 주어진다. 이 주소는 최대 39글자이다. 또한, 주소는 숫자 0-9, 알파벳 소문자 a-f, 콜론 :으로만 이루어져 있다.

www.acmicpc.net

문제

IPv6은 길이가 128비트인 차세대 인터넷 프로토콜이다.

IPv6의 주소는 32자리의 16진수를 4자리씩 끊어 나타낸다. 이때, 각 그룹은 콜론 (:)으로 구분해서 나타낸다.

예를 들면, 다음과 같다.

2001:0db8:85a3:0000:0000:8a2e:0370:7334

32자리의 16진수는 사람이 읽고 쓰기에 불편하고, 대부분의 자리가 0이기 때문에 아래와 같이 축약할 수 있다.

  1. 각 그룹의 앞자리의 0의 전체 또는 일부를 생략 할 수 있다. 위의 IPv6을 축약하면, 다음과 같다
2001:db8:85a3:0:00:8a2e:370:7334
  1. 만약 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;
}

 

반응형

댓글