본 문제는 2진수와 16진수 사이의 상호 변환을 수행하고, 변환 결과가 회문(palindrome)인지 여부를 판단하는 프로그램을 작성하는 것을 목표로 한다. 입력된 숫자가 16진수일 경우 2진수로, 2진수일 경우 16진수로 변환하며, 변환 후 결과 값이 앞뒤로 동일하게 읽히면 "Beautiful"이라는 문구를 출력 전에 추가로 표시해야 한다.
예를 들어, 16진수 F.E는 2진수로 변환하면 1111.1110이 되며, 소수점 끝의 불필요한 0을 제거하여 1111.111로 출력한다. 반대로 2진수 1111.1111은 16진수로 변환하면 F.F가 되고, 이 값은 회문이므로 앞에 "Beautiful"을 붙여 출력한다.
입력 형식
- 여러 개의 테스트 케이스가 주어지며, 각 줄에는 진법(base)과 해당 진법의 숫자 문자열(str)이 주어진다.
- base는 2 또는 16이며, str은 정수 또는 실수 형태의 유효한 2진수 또는 16진수이다.
- 입력되는 문자열 전체 길이의 합은 최대 106이다.
출력 형식
- 각 케이스에 대해 변환된 값을 출력한다.
- 변환 결과에서 정수 부분의 선행 0과 소수 부분의 후행 0은 생략한다.
- 결과가 회문인 경우, 출력 문자열 앞에 "Beautiful "를 추가한다.
- 16진수 알파벳은 반드시 대문자로 출력한다.
알고리즘 설계
변환 로직은 다음과 같다:
- 16진수 → 2진수: 각 16진수 자릿수를 고정된 4비트 2진수로 매핑한다. 예: 'F' → "1111", 'E' → "1110". 소수점은 그대로 유지한다.
- 2진수 → 16진수: 소수점을 기준으로 정수부와 소수부를 나누고, 각각 오른쪽에서 왼쪽으로 4자리씩 끊어 16진수로 변환한다. 부족한 자리는 0으로 패딩한다.
- 형식 정리: 변환 후 정수부의 선행 0과 소수부의 후행 0을 제거한다. 만약 정수부가 비어 있으면 '0'으로 설정한다.
- 회문 판별: 최종 출력 문자열(소수점 포함)이 앞뒤로 동일한지 확인한다.
코드 구현
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <cctype>
using namespace std;
// 16진수 문자와 4비트 2진수 문자열 간 매핑
map<char, string> hexToBin = {
{'0', "0000"}, {'1', "0001"}, {'2', "0010"}, {'3', "0011"},
{'4', "0100"}, {'5', "0101"}, {'6', "0110"}, {'7', "0111"},
{'8', "1000"}, {'9', "1001"}, {'A', "1010"}, {'B', "1011"},
{'C', "1100"}, {'D', "1101"}, {'E', "1110"}, {'F', "1111"}
};
map<string, char> binToHex = {
{"0000", '0'}, {"0001", '1'}, {"0010", '2'}, {"0011", '3'},
{"0100", '4'}, {"0101", '5'}, {"0110", '6'}, {"0111", '7'},
{"1000", '8'}, {"1001", '9'}, {"1010", 'A'}, {"1011", 'B'},
{"1100", 'C'}, {"1101", 'D'}, {"1110", 'E'}, {"1111", 'F'}
};
// 문자열 앞뒤 공백 제거 및 정리
string trim(const string& s) {
int start = 0, end = s.size() - 1;
while (start <= end && s[start] == '0') start++;
while (end >= start && s[end] == '0') end--;
if (start > end) return "0";
return s.substr(start, end - start + 1);
}
// 소수점 기준 분리
pair<string, string> splitAtDot(const string& s) {
size_t pos = s.find('.');
if (pos == string::npos) return {s, ""};
return {s.substr(0, pos), s.substr(pos + 1)};
}
// 2진수 정수부를 16진수로 변환
string binaryIntegerToHex(string bin) {
if (bin.empty()) return "0";
while (bin.length() % 4 != 0) bin = "0" + bin;
string result;
for (int i = 0; i < bin.length(); i += 4) {
string chunk = bin.substr(i, 4);
result += binToHex[chunk];
}
// 선행 0 제거
int start = 0;
while (start < result.length() - 1 && result[start] == '0') start++;
return result.substr(start);
}
// 2진수 소수부를 16진수로 변환
string binaryFractionToHex(string bin) {
if (bin.empty()) return "";
while (bin.length() % 4 != 0) bin += "0";
string result;
for (int i = 0; i < bin.length(); i += 4) {
string chunk = bin.substr(i, 4);
result += binToHex[chunk];
}
return trim(result); // 후행 0 제거
}
// 16진수 문자열을 2진수 문자열로 변환
string hexToBinaryString(const string& hex) {
string result;
for (char c : hex) {
if (c == '.') {
result += '.';
} else {
result += hexToBin[toupper(c)];
}
}
return result;
}
// 회문 여부 확인
bool isPalindrome(const string& s) {
int left = 0, right = s.length() - 1;
while (left < right) {
if (s[left] != s[right]) return false;
left++; right--;
}
return true;
}
int main() {
int base;
string input;
while (cin >> base >> input) {
string converted = "";
if (base == 16) {
// 16진수 → 2진수
converted = hexToBinaryString(input);
// 정수부와 소수부 분리
auto [integerPart, fractionPart] = splitAtDot(converted);
// 정수부: 선행 0 제거
integerPart = trim("0" + integerPart); // 최소 한 자리 보장
// 소수부: 후행 0 제거
string finalResult = integerPart;
if (!fractionPart.empty()) {
fractionPart = trim(fractionPart);
if (!fractionPart.empty()) {
finalResult += "." + fractionPart;
}
}
converted = finalResult;
} else if (base == 2) {
// 2진수 → 16진수
auto [integerPart, fractionPart] = splitAtDot(input);
string hexInteger = binaryIntegerToHex(integerPart);
string hexFraction = binaryFractionToHex(fractionPart);
converted = hexInteger;
if (!hexFraction.empty()) {
converted += "." + hexFraction;
}
}
// 회문 여부 검사
if (isPalindrome(converted)) {
cout << "Beautiful ";
}
cout << converted << endl;
}
return 0;
}
입력 예제
16 F.E 2 1111.1111 16 0.0 16 E
출력 예제
1111.111 Beautiful F.F Beautiful 0 E
위 구현은 효율적인 맵핑을 통해 변환 시간을 최소화하며, 문자열 처리를 통해 출력 형식을 정확히 맞추고 회문 판별까지 수행한다.