Возможный дубликат:
Как преобразовать целочисленное значение в римскую цифровую строку?
впервые задаю вопрос здесь. У меня есть проект на горизонте, над которым я немного работаю, и я не могу найти ничего похожего на то, о чем он спрашивал здесь или в другом месте. Цель состоит в том, чтобы принять целое число без ограничения сверху и преобразовать его в римскую цифру. Поскольку целые числа на самом деле имеют верхнюю границу, я должен преобразовать ее в строку перед ее анализом, используя апострофы для обозначения каждого набора из трех символов, помещенных в подстроку. У меня возникают проблемы с концептуализацией циклов, которые а) назначают римские цифры тому, что они видят, исходя из их местоположения, б) подсчитывают каждый набор из трех, показывая апострофы.
Пока что у меня есть:
for(int i=0;i<(int)input.length()/3;i++){
temp=input.substr(i,3);
for(int j = 0; j < (int)temp.length(); j++){
if(j == 0){
if(temp[j] == '9') cout<<"CM";
else if(temp[j] >= '8') cout<<"DCCC";
else if(temp[j] >= '7') cout<<"DCC";
else if(temp[j] >= '6') cout<<"DC";
else if(temp[j] >= '5') cout<<"D";
else if(temp[j] == '4') cout<<"CD";
else if(temp[j] == '3') cout<<"CCC";
else if(temp[j] == '2') cout<<"CC";
else if(temp[j] == '1') cout<<"C";
}
else if(j == 1){
if(temp[j] == '9') cout<<"XC";
else if(temp[j] >= '8') cout<<"LXXX";
else if(temp[j] >= '7') cout<<"LXX";
else if(temp[j] >= '6') cout<<"LX";
else if(temp[j] >= '5') cout<<"L";
else if(temp[j] == '4') cout<<"XL";
else if(temp[j] == '3') cout<<"XXX";
else if(temp[j] == '2') cout<<"XX";
else if(temp[j] == '1') cout<<"X";
}
else if(j ==2){
if(temp[j] == '9') cout<<"IX";
else if(temp[j] == '8') cout<<"VIII";
else if(temp[j] == '7') cout<<"VII";
else if(temp[j] == '6') cout<<"VI";
else if(temp[j] >= '5') cout<<"V";
else if(temp[j] == '4') cout<<"IV";
else if(temp[j] == '3') cout<<"III";
else if(temp[j] == '2') cout<<"II";
else if(temp[j] == '1') cout<<"I";
}
}
}
Цифры отображаются достаточно хорошо сами по себе, но у меня возникают проблемы с выяснением того, как указать циклу запускаться справа и работать влево до трёх, поддерживая фактическое место числа на входе (например, 1234 должно отображать 1 как я, а не C. Мне также нужно выяснить цикл для записи в апострофах.
Самый простой способ, которым я могу придумать, чтобы преобразовать в римские цифры, это проверить, начиная с максимально возможной цифры / комбинации, и перейти вниз. Включите комбо и проверяйте их от самого большого до самого маленького, так что, скажем, «XC» всегда проверяется перед «L», и вам не нужно беспокоиться о «LXXXX» и «LXL» и тому подобное.
// This code requires C++11 support. Namely, initializer lists and type inference.
// If your compiler sucks, there's equivalents for the important stuff. What really
// really matters is the order of the value=>digits mappings, and the iteration over
// them in the for loop.
#include <vector>
#include <string>
#include <utility>
std::string romanNumeralFor(int n, int markCount = 0) {
typedef std::pair<int, std::string> valueMapping;
static std::vector<valueMapping> importantNumbers = {
{1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"},
{100, "C"}, { 90, "XC"}, { 50, "L"}, { 40, "XL"},
{10, "X"}, { 9, "IX"}, { 5, "V"}, { 4, "IV"},
{1, "I"},
};
std::string result;
bool needMark = false;
std::string marks(markCount, '\'');
for (auto mapping : importantNumbers) {
int value = mapping.first;
std::string &digits = mapping.second;
while (n >= value) {
result += digits;
n -= value;
needMark = true;
}
if ((value == 1000 || value == 100 || value == 10 || value == 1) && needMark) {
result += marks;
needMark = false;
}
}
return result;
}
Что касается преобразования строки в число:
// in C++11
int n = std::stoi(str);
// in C++03
std::istringstream iss(str);
int n;
iss >> n;
Итак, разбейте вашу строку на трехзначные куски (начиная с конца!) И передайте их с соответствующим количеством меток.
Не лучшее решение, но оно работает.
#include <iostream>
#include <map>
#include <algorithm>
#include <string>
void replaceAll(std::string& str, const std::string& from, const std::string& to) {
if(from.empty())
return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
}
int romanNumeralToInt(std::string s) {
std::map<char,int> romanNum = {
{'I',1}, {'V',5}, {'X',10}, {'L',50}, {'C',100},
{'D',500}, {'M',1000}
};
//{"IIIII",5}, {"VV",10}, {"XXXXX",50}, {"LL",100}, {"CCCCC",500}, {"DD",1000}
int g = 0;
std::sort(s.begin(),s.end());
if(s.find("IIIII") != std::string::npos)
replaceAll(s,"IIIII","V");
if(s.find("VV") != std::string::npos)
replaceAll(s,"VV","X");
if(s.find("XXXXX") != std::string::npos)
replaceAll(s,"XXXXX","L");
if(s.find("LL") != std::string::npos)
replaceAll(s,"LL","C");
for(auto& i : s) {
if(romanNum[i] != 0)
g += romanNum[i];
}
return g;
}
int main() {
std::string st = "XXXXXIIIIIVVVXLLD";
int a = romanNumeralToInt(st);
std::cout << a;
}
Распечатывает 680.