문제 설명
당신은 덧셈 혹은 뺄셈 수식이 여러 개 적힌 고대 문명의 유물을 찾았습니다. 이 수식들을 관찰하던 당신은 이 문명이 사용하던 진법 체계가 10진법이 아니라는 것을 알아냈습니다. (2 ~ 9진법 중 하나입니다.)
수식들 중 몇 개의 수식은 결괏값이 지워져 있으며, 당신은 이 문명이 사용하던 진법에 맞도록 지워진 결괏값을 채워 넣으려 합니다.
다음은 그 예시입니다.
<수식>
14 + 3 = 17
13 - 6 = X
51 - 5 = 44
- X로 표시된 부분이 지워진 결괏값입니다.
51 - 5 = 44에서 이 문명이 사용하던 진법이 8진법임을 알 수 있습니다. 따라서 13 - 6 = X의 지워진 결괏값을 채워 넣으면 13 - 6 = 5가 됩니다.
다음은 또 다른 예시입니다.
<수식>
1 + 1 = 2
1 + 3 = 4
1 + 5 = X
1 + 2 = X
주어진 수식들에서 이 문명에서 사용한 진법이 6 ~ 9진법 중 하나임을 알 수 있습니다.
1 + 5 = X의 결괏값은 6진법일 때 10, 7 ~ 9진법일 때 6이 됩니다. 이와 같이 결괏값이 불확실한 수식은 ?를 사용해 1 + 5 = ?와 같이 결괏값을 채워 넣습니다.
1 + 2 = X의 결괏값은 6 ~ 9진법에서 모두 3으로 같습니다. 따라서 1 + 2 = X의 지워진 결괏값을 채워 넣으면 1 + 2 = 3이 됩니다.
덧셈 혹은 뺄셈 수식들이 담긴 1차원 문자열 배열 expressions가 매개변수로 주어집니다. 이때 결괏값이 지워진 수식들의 결괏값을 채워 넣어 순서대로 문자열 배열에 담아 return 하도록 solution 함수를 완성해 주세요.
제한사항
- 2 ≤ expressions의 길이 ≤ 100
- expressions의 원소는 "A + B = C" 혹은 "A - B = C" 형태의 문자열입니다. A, B, C와 연산 기호들은 공백 하나로 구분되어 있습니다.
- A, B는 음이 아닌 두 자릿수 이하의 정수입니다.
- C는 알파벳 X 혹은 음이 아닌 세 자릿수 이하의 정수입니다. C가 알파벳 X인 수식은 결괏값이 지워진 수식을 의미하며, 이러한 수식은 한 번 이상 등장합니다.
- 결괏값이 음수가 되거나 서로 모순되는 수식은 주어지지 않습니다.
풀이
가능한 진법의 범위를 좁히거나, 특정시키는 방법을 생각해 내는 문제.
- 진법의 범위 좁히기 : {수식에 사용된 최대 기수 + 1} 이 최소 진법임.
예를 들면 [ 55 + 55 = X ] 이라는 수식이 있을 때, 사용된 최대 기수는 5 이다.
그렇다면 이 문제에서 가능한 진법은 6(5 + 1)진법 ~ 9진법 이다.
- 진법 특정 시키기 : 수식의 계산 결과가 10진법으로 계산한 결과와 다를 경우, 진법(N)을 특정 가능하다.
왜냐하면 10진법과 다르다는 것은 N 진법으로 계산한 결과 올림 혹은 내림이 발생했다는 뜻이고, 이럴 경우 올림된 나머지가 N에 의해 정해지기 때문에 단 한 가지 진법으로 특정 가능하다.
여기서 N을 계산해 내는 방법은 단순히 범위 내의 모든 진법(N)에 대해서 결과를 계산하고 맞는지 비교해 보면 된다.
- 좁혀진 진법 범위로 결과가 X인 수식의 결과 계산하기.
최소 진법과 최대 진법을 한 번씩 계산해 보고, 두 계산 결과가 같으면 X를 특정할 수 있다.
두 계산 결과가 다를 경우 결과 값을 ? 로 둔다.
코드
#include <string>
#include <vector>
#include <cmath>
#include <iostream>
#include <sstream>
using namespace std;
int MinN = 2;
int MaxN = 9;
vector<string> SplitExp(string exp)
{
stringstream ss(exp);
vector<string> splitedExp(5);
int i = 0;
while(ss>>splitedExp[i++]);
return splitedExp;
}
int ToDecimal(int number, int N)
{
int result = 0;
int digit = 1;
int numerator = number;
while(numerator != 0)
{
result += numerator%10 * digit;
digit *= N;
numerator /= 10;
}
return result;
}
int ToNSystem(int number,int N)
{
int numerator = number;
int result = 0;
int digit = 1;
while(numerator != 0)
{
result += numerator%N *digit;
digit *= 10;
numerator /= N;
}
return result;
}
string SolveExp(string A, string B, bool add, int N)
{
int ADecimal = ToDecimal(stoi(A),N);
int BDecimal = ToDecimal(stoi(B),N);
// cout <<"ADecimal : "<<ADecimal<<endl;
//cout <<"BDecimal : "<<BDecimal<<endl;
int resultDecimal = add? ADecimal+BDecimal : ADecimal-BDecimal;
string result = "";
result = to_string(ToNSystem(resultDecimal,N));
return result;
}
int SpecifyN(vector<vector<string>>& nonXExps)
{
for(auto exp : nonXExps)
{
int reusultDecimal = exp[1] == "+" ?
stoi(exp[0]) + stoi(exp[2])
: stoi(exp[0]) - stoi(exp[2]);
if(reusultDecimal == stoi(exp[4]))
continue;
for(int i = MinN ; i <= MaxN ; i++)
{
string resultN = SolveExp(exp[0], exp[2], exp[1] == "+", i);
if(resultN == exp[4])
return i;
}
}
return -1;
}
vector<string> solution(vector<string> expressions) {
vector<string> answer;
vector<vector<string>> nonXExps;
vector<vector<string>> xExps;
for(auto exp : expressions)
{
vector<string> splitedExp = SplitExp(exp);
for(auto token : splitedExp)
{
for(auto c : token)
if(c >= '0' && c <= '9')
MinN = max(c-'0'+1, MinN);
}
if(splitedExp[4] == "X")
xExps.push_back(splitedExp);
else
nonXExps.push_back(splitedExp);
}
int SpecifyResult = SpecifyN(nonXExps);
if(SpecifyResult > 0)
{
MinN = SpecifyResult;
MaxN = SpecifyResult;
}
cout<<"MinN : "<<MinN<< ", MaxN : "<<MaxN<<endl;
for(auto exp : xExps)
{
string minX =SolveExp(exp[0], exp[2], exp[1] == "+", MinN);
string maxX =SolveExp(exp[0], exp[2], exp[1] == "+", MaxN);
exp[4] = minX == maxX ? minX : "?";
string ans = "";
for(auto t : exp)
ans += t +" ";
ans.erase(ans.end()-1);
answer.push_back(ans);
}
return answer;
}'알고리즘 문제 풀이' 카테고리의 다른 글
| [프로그래머스] 등대 (0) | 2025.09.03 |
|---|---|
| [프로그래머스] 아이템 줍기 (0) | 2025.08.20 |
| [백준] 14501 퇴사 (0) | 2025.07.18 |
| [백준]4811 알약 (0) | 2025.07.18 |
| [백준] 1107 리모컨 (1) | 2025.06.10 |