Форум программистов, компьютерный форум CyberForum.ru

задача на римскую систему счисления - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 44, средняя оценка - 4.84
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
08.12.2011, 23:12     задача на римскую систему счисления #1
Ввести число римскими цифрами (менее 4000 в арабской записи), учитывая следующие обозначения:
I - 1, V - 5, X - 10, L - 50, C - 100, D - 500, M - 1000.
Проверить правильность ввода исходных данных и напечатать это число арабскими цифрами.

у меня получилось как-то вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <string.h> 
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main ()
{
     char s[256], m;
        int n, c, c1, i, a, k;
        
        printf("Vvedite chislo: ");
        scanf("%s", s); 
        k=strlen(s);
        
        for (i = 0; i < k; i++)   
        { if ((s[i] != 'I') &&  (s[i] != 'V') && (s[i] != 'X') && //проверка
        (s[i] != 'L') && (s[i] != 'C') && 
        (s[i] != 'D') && (s[i] != 'M')) exit (0);}; 
        
        for (i = 0, c = 0, n = 0; i < k; i++)
        {
                c1 = c;
                
                if (s[i] == 'I')
                        c = 1;
                        
                if (s[i] == 'V')
                        c = 5;
 
                if (s[i] == 'X')
                        c = 10;
 
                if (s[i] == 'L')
                        c = 50;
 
                if (s[i] == 'C')
                        c = 100;
 
                if (s[i] == 'D')
                        c = 500;
 
                if (s[i] == 'M')
                        c = 1000;
 
                if (c > c1)
                        a = -2 * c1;
                else
                    a = 0;
 
                n = n + a + c;
        }
 
        printf("Vashe chislo: %d", n);
        getch();
        return 0;
}
Но. Непонятно как исключить из этого запись вида IIII (там же не должно быть повторение четырех одинаковых символов подряд), запись вида IIX (левее большего значения может стоять только одна I) и запись вида XIXX (символ I, стоящий перед большим, может быть только предпоследним в строке, а последним должен быть символ больший I и только один).

Кому не сложно, помогите пожалуйста. Желательно доработать этот код))
Заранее спасибо!

Добавлено через 20 часов 13 минут
up)))))

Добавлено через 3 часа 9 минут
up.....
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.12.2011, 23:12     задача на римскую систему счисления
Посмотрите здесь:

C++ Простейший алгоритм перевода числа из 10 системы счисления в 16 ричную систему счисления
C++ Перевод натурального числа из десятичной системы счисления в систему счисления по основанию
C++ Перевод чисел из двоичной системы счисления в систему счисления кратной степеням двойки и обратно
C++ Перевод с арабской на римскую сисстему счисления
задача на перевод числа из 10 в 2 систему счисления C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
greeezz
272 / 165 / 4
Регистрация: 10.07.2011
Сообщений: 441
09.12.2011, 06:22     задача на римскую систему счисления #2
не претендую на оригинальность решения. просто понравилась ваша задача и решил попробовать.
заметка. к исключением которые вы предлагаете я добавил еще и VX, LC и DM. Думаю такого тоже не может быть
результат получился такой:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
 
bool isCorrectLetter(const char &letter) {    //проверка символов
    const int size = 7;
    char mySymbols[size] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
    for (int i = 0; i < size; ++i) {
        if (letter == mySymbols[i]) {
            return true;
        }
    }
    return false;
}
 
//првоерка последовательности
bool isCorrectSequence(const char &previous, const char &next, int &recurrence) {
    if (next == previous && (previous == 'L' || previous == 'D' || previous == 'V')) {
        return false;
    }
    if (recurrence == 3 && (next == 'X' || next == 'C' || next == 'M' || next == 'I')) {
        return false;
    }
    if ((next == 'X' && previous == 'V') || (next == 'C' && previous == 'L') || (next == 'M' && previous == 'D')) {
        return false;
    }
 
    return true;
}
 
 
//конвертация из риских в арабские
int getArabNumber(const char &rimNumber){
    switch(rimNumber){
    case 'I':
        return 1;
    case 'V':
        return 5;
    case 'X':
        return 10;
    case 'L':
        return 50;
    case 'C':
        return 100;
    case 'D':
        return 500;
    case 'M':
        return 1000;
    }
    return 0;
}
 
 
//вычесление результата
int calculation(const char array[], const int &count){
    int res = 0;
    int prev = 0, next;
    for(int i=count; i >= 0; --i){
        next = getArabNumber(array[i]);
        if(prev > next){
            res = (res - prev) + (prev - next);
        } else {
            res +=next;
        }
        prev = next;
 
    }
    return res;
}
 
int main() {
    const int size = 256;
    char s[size], next, previous;
    int i, recurrence = 0;
    bool isCorrect = true;
 
    cout << "PLEASE ENTER THE ROMAN NUMERAL ::\n>";
    for (i = 0; (next = cin.get()) != '\n'; ++i) {
        if (i == 0) {
            s[i] = next;
            previous = next;
        } else {
            if (previous == next)
                recurrence++;
            else
                recurrence = 0;
            if (isCorrectLetter(next) && isCorrectSequence(previous, next, recurrence)) {
                s[i] = next;
                previous = next;
            } else {
                isCorrect = false;
                break;
            }
        }
    }
    if (!isCorrect || (s[i - 3] == 'I' && s[i - 2] != 'I')) {
        cout << "Provided number is not correct";
    } else {
        cout << "Provided number is correct :: " << s << endl;
        cout << "COnverted result           :: " << calculation(s, i-1);
    }
 
 
    cin.get();
    return 0;
}
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
12.12.2011, 23:46  [ТС]     задача на римскую систему счисления #3
greeezz, я сейчас потестила Ваш код. у меня запись вида "VIV" пропускает. Хотя она, по идее, невозможна. пыталась сама поправить, еще больше запуталась, так ничего и не получилось.

Не очень понятно, что считает переменная
Цитата Сообщение от greeezz Посмотреть сообщение
recurrence
и почему здесь

Цитата Сообщение от greeezz Посмотреть сообщение
if (recurrence == 3 && (next == 'X' || next == 'C' || next == 'M' || next == 'I')) { return false;
она равняется именно трем.
И не понятно, зачем здесь перед isCorrect стоит !
Цитата Сообщение от greeezz Посмотреть сообщение
if (!isCorrect || (s[i - 3] == 'I' && s[i - 2] != 'I'))

Надеюсь, не очень завалила глупыми вопросами?
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
12.12.2011, 23:52     задача на римскую систему счисления #4
Перевод римских чисел в арабские и наоборот
там есть вроде как рабочий код. если с stl дружите, то поймете что так и как. + пара ссылок на другие решения.
хм. VIV прожевывает. надо подправить
greeezz
272 / 165 / 4
Регистрация: 10.07.2011
Сообщений: 441
12.12.2011, 23:53     задача на римскую систему счисления #5
Цитата Сообщение от ПаЗитиФкА Посмотреть сообщение
Надеюсь, не очень завалила глупыми вопросами?
вопросы не глупые. на самом деле мое решение не очень очевидное. думаю есть варианты намного проще. я вам отвечу на ваши вопросы чуть позже. думаю вернусь часа через полтора и отвечу.
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
12.12.2011, 23:53  [ТС]     задача на римскую систему счисления #6
DU, stl?
эх, как много нынче люди ждут от девушки) знать бы еще что stl такое....)
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
13.12.2011, 00:27     задача на римскую систему счисления #7
Я поправил пример. добавил пару камментов. Скопируйте все себе и попробуйте запустить.
В main идет заполнение эталонных данных. Это пары - римское число и десятичное. В случае плохих чисел - идут пары с BAD_VALUE. Все это засовывается в динамичесский массив и потом каждая пара тестится в ф-ии CheckConversion. Если результат конверсии совпадает с эталоном - все ок, иначе выводится ошибка.

само преобразование построено на заранее определенной таблице и трех ф-иях.
C++
1
2
3
bool StartsWith(const string& romeVal, const string& pattern);
string GetFirstRomeValue(const string& romeVal);
unsigned RomeToDec(const string& romeVal);
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <map>
 
using namespace std;
 
///////////////////////////////////////////////////////////////////////////
 
void ThrowEmptyStringError()
{
  throw string("Rome value is empty string.");
}
 
void ThrowBadFormatError(const string& val)
{
  throw "The \"" + val + "\" has incorrect rome number format.";
}
 
void ThrowOutOfRangeOrBadFormatError(const string& val)
{
  throw "The \"" + val + "\" is greater than 3999 or has incorrect rome number format.";
}
 
void ThrowBadConversionError(const string& romeVal, const unsigned correctVal, unsigned conversionResult)
{
  ostringstream oss;
  oss << "The \"" + romeVal + " == " << correctVal << "\" is converted to " << conversionResult << ".";
  throw string(oss.str());
}
 
///////////////////////////////////////////////////////////////////////////
 
const unsigned BAD_VALUE = (unsigned) -1;
typedef pair<string, unsigned> RomeDecPair;
typedef map<string, unsigned> Table;
Table g_table;
 
void InitTables()
{
  g_table["I"] = 1;
  g_table["II"] = 2;
  g_table["III"] = 3;
  g_table["IV"] = 4;
  g_table["V"] = 5;
  g_table["VI"] = 6;
  g_table["VII"] = 7;
  g_table["VIII"] = 8;
  g_table["IX"] = 9;
  g_table["X"] = 10;
  g_table["XX"] = 20;
  g_table["XXX"] = 30;
  g_table["XL"] = 40;
  g_table["L"] = 50;
  g_table["XC"] = 90;
  g_table["C"] = 100;
  g_table["CC"] = 200;
  g_table["CCC"] = 300;
  g_table["CD"] = 400;
  g_table["D"] = 500;
  g_table["CM"] = 900;
  g_table["M"] = 1000;
  g_table["MM"] = 2000;
  g_table["MMM"] = 3000;
}
 
bool StartsWith(const string& romeVal, const string& pattern)
{
  // Проверка, начинается ли romeVal со строки pattern.
  // romeVal = 123456, pattern = 123, result = true
  // romeVal = 123456, pattern = ab, result = false
 
  if (romeVal.length() >= pattern.length())
    return romeVal.substr(0, pattern.length()) == pattern;
  return false;
}
 
string GetFirstRomeValue(const string& romeVal)
{
  // Возвращает первое распознанное число в строке romeVal или кидает исключение.
  // Поиск числа идет по таблице и возвращается максимальное из всех возможных.
  // Для чила IX возможные кандитаты - это I и IX. Т.к. IX > I результат будет равен IX.
  // romeVal = CIX, result = C
  // romeVal XLII, result = XL
  // romeVal = ABX, throws excepction
 
  unsigned maxDecVal = 0;
  const string* result = 0;
  for (Table::const_iterator it = g_table.begin(), end = g_table.end(); it != end; ++it)
  {
    const string& currentRomeVal = it->first;
    const unsigned currentDecVal = it->second;
    if (StartsWith(romeVal, currentRomeVal) && currentDecVal > maxDecVal)
    {
      if (currentRomeVal.length() == 1)
      {
        // Если число односимвольное, проверяем, не встретилась ли комбинация вроде
        // IIII, XXXX, LLLL, ...
        if (StartsWith(romeVal, string(4, currentRomeVal[0])))
          ThrowBadFormatError(romeVal);
      }
 
      result = &currentRomeVal;
      maxDecVal = currentDecVal;
    }
  }
 
  if (result == 0)
    ThrowBadFormatError(romeVal);
 
  return *result;
}
 
unsigned RomeToDec(const string& romeVal)
{
  if (romeVal.empty())
    ThrowEmptyStringError();
 
  string str = romeVal;
  unsigned result = 0;
  unsigned prevDecVal = 0;
  while (!str.empty())
  {
    const string tmpRomeVal = GetFirstRomeValue(str);
    const unsigned tmpDecVal = g_table[tmpRomeVal];
 
    if (prevDecVal != 0)
    {
      // Если мы тут, значит это не первая итерация в цикле.
      // У нас есть предыдущее распознанное число.
 
      if (prevDecVal < 10)
      {
        // числа меньше 10 всегда должны быть последними. Если уже встречалось число,
        // которое меньше 10, значит что-то не так  с форматом римского числа.
        ThrowBadFormatError(romeVal);
      }
 
      if (prevDecVal <= tmpDecVal)
      {
        // Последующее число всегда должно быть меньше прерыдущего.
        // Eсли это не так, то что-то не то с форматом римского числа.
        ThrowBadFormatError(romeVal);
      }
    }
 
    prevDecVal = tmpDecVal;
    result += tmpDecVal;
 
    if (result >= 4000)
      ThrowOutOfRangeOrBadFormatError(romeVal);
 
    // Вычитание из str строки tmpRomeVal.
    // Например, если str == "XVII", а tmpRomeVal == "X", то после вызова substr, переменная
    // str будет равна VII. После этого цикл повторяется уже для строки str="VII"
    str = str.substr(tmpRomeVal.length());
  }
 
  return result;
}
 
///////////////////////////////////////////////////////////////////////////
 
void CheckConversion(const RomeDecPair& test)
{
  try
  {
    const unsigned result = RomeToDec(test.first);
    if (result == test.second)
    {
      cout << test.first << " == " << test.second << endl;
    }
    else
    {
      ThrowBadConversionError(test.first, test.second, result);
    }
  }
  catch (const string& errDescr)
  {
    cout << (test.first.empty() ? "#empty#" : test.first.c_str()) << ": failed : " << errDescr << endl;
  }
}
 
int main()
{
  InitTables();
 
  vector<RomeDecPair> tests;
 
  tests.push_back(make_pair("I", 1));
  tests.push_back(make_pair("II", 2));
  tests.push_back(make_pair("III", 3));
  tests.push_back(make_pair("IV", 4));
  tests.push_back(make_pair("V", 5));
  tests.push_back(make_pair("VI", 6));
  tests.push_back(make_pair("VII", 7));
  tests.push_back(make_pair("VIII", 8));
  tests.push_back(make_pair("IX", 9));
  tests.push_back(make_pair("X", 10));
  tests.push_back(make_pair("XI", 11));
  tests.push_back(make_pair("XII", 12));
  tests.push_back(make_pair("XIII", 13));
  tests.push_back(make_pair("XIV", 14));
  tests.push_back(make_pair("XV", 15));
  tests.push_back(make_pair("XVI", 16));
  tests.push_back(make_pair("XVII", 17));
  tests.push_back(make_pair("XVIII", 18));
  tests.push_back(make_pair("XIX", 19));
  tests.push_back(make_pair("XX", 20));
  tests.push_back(make_pair("XXI", 21));
  tests.push_back(make_pair("XL", 40));
  tests.push_back(make_pair("XLII", 42));
  tests.push_back(make_pair("LIX", 59));
  tests.push_back(make_pair("LXXVII", 77));
  tests.push_back(make_pair("XC", 90));
  tests.push_back(make_pair("CX", 110));
  tests.push_back(make_pair("CDXCIX", 499));
  tests.push_back(make_pair("DLXXXIII", 583));
  tests.push_back(make_pair("DCCCLXXXVIII", 888));
  tests.push_back(make_pair("MDCLXVIII", 1668));
  tests.push_back(make_pair("MCMLXXXIX", 1989));
  tests.push_back(make_pair("MMMCMXCIX", 3999));
 
  tests.push_back(make_pair("", BAD_VALUE));
  tests.push_back(make_pair("VIV", BAD_VALUE));
  tests.push_back(make_pair("VIIX", BAD_VALUE));
  tests.push_back(make_pair("VIIV", BAD_VALUE));
  tests.push_back(make_pair("VIIXL", BAD_VALUE));
  tests.push_back(make_pair("IIIV", BAD_VALUE));
  tests.push_back(make_pair("IIV", BAD_VALUE));
  tests.push_back(make_pair("IIII", BAD_VALUE));
  tests.push_back(make_pair("IIX", BAD_VALUE));
  tests.push_back(make_pair("XIIII", BAD_VALUE));
  tests.push_back(make_pair("XIIIIX", BAD_VALUE));
  tests.push_back(make_pair("XIIIIX", BAD_VALUE));
  tests.push_back(make_pair("XXXX", BAD_VALUE));
  tests.push_back(make_pair("LL", BAD_VALUE));
  tests.push_back(make_pair("CLC", BAD_VALUE));
  tests.push_back(make_pair("CLL", BAD_VALUE));
  tests.push_back(make_pair("DLD", BAD_VALUE));
  tests.push_back(make_pair("LDD", BAD_VALUE));
  tests.push_back(make_pair("LLI", BAD_VALUE));
  tests.push_back(make_pair("MMMCMXCX", BAD_VALUE));
  tests.push_back(make_pair("AXX", BAD_VALUE));
  tests.push_back(make_pair("LXA", BAD_VALUE));
 
  for (vector<RomeDecPair>::const_iterator it = tests.begin(), end = tests.end(); it != end; ++it)
  {
    CheckConversion(*it);
  }
 
  return 0;
}
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
13.12.2011, 00:30  [ТС]     задача на римскую систему счисления #8
DU, спасибо за проделанную работу, но у меня стойкое ощущение что я этот код никогда не пойму. постараюсь, конечно, разобраться, но вряд ли мозгов хватит
если учесть что на лекциях нам прочитали только циклы, массивы и чуть начали строки..
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
13.12.2011, 00:47     задача на римскую систему счисления #9
чтобы понять это вам нужно откопать самостоятельно инфу по следующим штукам:
C++
1
2
3
4
5
6
7
8
9
10
11
std::string
std::pair<First, Second>; // В программе встречается pair<string, unsigned>. это по смыслу то же самое, что и 
struct RomeDecPair
{
  string first;
  unsigned second;
};
std::vector // в частности его ф-ию push_back().
std::map
 
// + базовые знания об исключениях в с++. что это и как с ними работать.
В любом нормальном учебнике это должно быть. все эти штуки - часть стандартной библиотеки а значит и часть языка C++.
Потраченное на изучение всего этого время еще окупится.
greeezz
272 / 165 / 4
Регистрация: 10.07.2011
Сообщений: 441
13.12.2011, 01:36     задача на римскую систему счисления #10
Цитата Сообщение от ПаЗитиФкА Посмотреть сообщение
Не очень понятно, что считает переменная
recurrence
данная переменная считает количество повторение текущей римской цифры.
C++
1
2
3
4
if (previous == next)
       recurrence++;
else
        recurrence = 0;
если цифра сменилась то счетчик сбрасывается.
Цитата Сообщение от ПаЗитиФкА Посмотреть сообщение
и почему здесь
if (recurrence == 3 && (next == 'X' || next == 'C' || next == 'M' || next == 'I')) { return false;
замените на код ниже. Будет тот же результат. Тут по идее проверяется что одна и таже чифра не может повторяться более трех раз подряд.
C++
1
2
3
if (recurrence == 3 && next > 0) {
        return false;
}
Цитата Сообщение от ПаЗитиФкА Посмотреть сообщение
И не понятно, зачем здесь перед isCorrect стоит !
if (!isCorrect || (s[i - 3] == 'I' && s[i - 2] != 'I'))
потому что переменная isCorrect имеет тип булеан. и как результат всего два возможных варианта значения . true или false.
!isCorrect
это то же самой что и
isCorrect == false

насчет последовтельности VIV
поставил временную заплатку в функцию.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
bool isCorrectSequence(const char arr[], const int &iter, const char next, int &recurrence) {
    char previous;
    previous = arr[iter-1];
        if (next == previous && (previous == 'L' || previous == 'D' || previous == 'V')) {
                return false;
        }
        if (recurrence == 3 && next > 0) {
                return false;
        }
        if ((next == 'X' && previous == 'V') || (next == 'C' && previous == 'L') || (next == 'M' && previous == 'D')) {
                return false;
        }
        if(next == 'V' && previous == 'I' && arr[iter-2] == 'V') {
            return false;
        }
        return true;
}
в main замените вызов функции на вот такой:
C++
1
isCorrectSequence(s, i, next, recurrence)
если есть еще вопросы задавайте.
Я пересмотрю в свободное время код. возможно передаю на более простой и понятный.
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
13.12.2011, 09:24  [ТС]     задача на римскую систему счисления #11
greeezz, вроде бы все понятно. спасибо огромное за помощь!)
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
14.12.2011, 21:27  [ТС]     задача на римскую систему счисления #12
greeezz, я тут отчет села делать по этой программе. и немного не поняла эту строчку
Цитата Сообщение от greeezz Посмотреть сообщение
for (i = 0; (next = cin.get()) != '\n'; ++i)
т.е. тут посимвольный ввод получается? (или как его назвать). Вводим символ, выполняем весь цикл, потом опять вводим символ и снова выполняем цикл? и так до тех пор, пока не будет нажат Enter? я правильно понимаю?
greeezz
272 / 165 / 4
Регистрация: 10.07.2011
Сообщений: 441
15.12.2011, 02:44     задача на римскую систему счисления #13
Цитата Сообщение от ПаЗитиФкА Посмотреть сообщение
не поняла эту строчку
C++
1
for (i = 0; (next = cin.get()) != '\n'; ++i)
здесь с каждой итерацией сначала получается сивол из входящего потока и записвается в переменную next. Затем если значение переменной next не равное концу строки то выполняется итерация цикла.


ПаЗитиФкА, я написал другу версию программы. основные функции остались те же. изменилась логика чтения римского числа из входного потока и проверка последовательности.
К сожалению старая версия программы работает не корректно. К примеру в старой версии ошибочное число XMMXMXX будет считаться правильным.
ТЕСТЫ

TRUE
4 IV 1
9 IX 1
40 XL 1
90 XC 1
400 CD 1
900 CM 1
2011 MMXI 1
2009 MMIX 1
99 XCIX 1
46 XLVI 1
31 XXXI 1
8 VIII 1
888 DCCCLXXXVIII 1
1668 MDCLXVIII 1
1989 MCMLXXXIX 1
3999 MMMCMXCIX 1
583 DLXXXIII 1
32 XXXII 1
2010 MMX 1
21 XXI 1
3 III 1

FALSE
XXXX 0
XXIXX 0
HLL 0
IIV 0
VVX 0
VXV 0
IVI 0
XLX 0
LCL 0
IVV 0
IXX 0
XLL 0
XCC 0
CDD 0
CMM 0
LXL 0
VIV 0
DCD 0
XXIXX 0
MDXCLXIVIL 0
MDCILXIVIIX 0
MDMMCLXIVICI 0

Я написал комментарии в непонятных на мой взгляд местах кода. посомтрите может этот вамриант вам больше понравится. Ну а если что непонятно то спрашивайте конечно.
КОД ПРОГРАММЫ

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include <cstdlib>   // тут std::system
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
 
int getArabNumber(const char &);
bool isCorrectLetter(const char &);
bool getRomanNumeral(char[], int &);
bool checkSequence(const char[], const int &);
int getSubtractingSequence(const char&, const char&);
int calculation(const char[], const int &);
 
int main() {
    const int size = 25;
    char romanNumeral[size];
    bool exit = false, isCorrectNumber;
    int actualSize;
 
    while (!exit) {
        actualSize = size;
        romanNumeral[0] = '\0';
        isCorrectNumber = false;
 
        cout << "Please enter Roman Numeral\n>";
        if (getRomanNumeral(romanNumeral, actualSize)) {
            if (checkSequence(romanNumeral, actualSize)) {
                isCorrectNumber = true;
            }
        }
        if (isCorrectNumber) {
            cout << calculation(romanNumeral, actualSize) << endl;
        } else {
            cout << "Provided Romam numeral is incorrect.\n";
        }
 
        cout << "\n1 :: Try once againe\n2 :: EXIT\n>";
        if (cin.get() == '2') {
            exit = true;
        }
        cin.clear();
        cin.ignore(1000, '\n');
        system("CLS");
    }
    return 0;
}
 
//вычесление результата
int calculation(const char array[], const int &count) {
    int res = 0;
    int prev = 0, next;
    for (int i = count; i >= 0; --i) {
        next = getArabNumber(array[i]);
        if (prev > next) {
            res = (res - prev) + (prev - next);
        } else {
            res += next;
        }
        prev = next;
 
    }
    return res;
}
 
bool checkSequence(const char romanNumeral[], const int &actualSize) {
    int substrResult = 0;
 
    for (int i = actualSize - 1; i >= 0; --i) {
        if (i > 1) {
            /*исключаем последовательности типа:  VXV, IVI, XLX, LCL, LXL, VIV, DCD */
            if (romanNumeral[i] == romanNumeral[i - 2] && romanNumeral[i] != romanNumeral[i - 1]) {
                if (getArabNumber(romanNumeral[i - 1]) % getArabNumber(romanNumeral[i]) == 0
                        || getArabNumber(romanNumeral[i]) / getArabNumber(romanNumeral[i - 1]) == 5) {
                    return false;
                }
                /*исключаем последовательности типа:  IVV, IXX, XLL, XCC, CDD, CMM */
            } else if (romanNumeral[i] == romanNumeral[i - 1]) {
                if (getArabNumber(romanNumeral[i - 2]) < getArabNumber(romanNumeral[i - 1])) {
                    return false;
                }
            }
        }
        if (substrResult > 0 && getArabNumber(romanNumeral[i]) <= substrResult) {
            //cout << "3" << endl;
            return false; //цифра следующая слева от пары требующей вычитания должна быть
                          //больше разности
        } else {
            //cout << "4" << endl;
            if (i > 0) { //двишаемся далее по массиву для обработки следующей пары (если такая есть)
                //cout << "5" << endl;
                --i;
                //cout << romanNumeral[i] << " " <<  romanNumeral[i + 1] << endl;
                if (getArabNumber(romanNumeral[i]) < getArabNumber(romanNumeral[i + 1])) {
                    substrResult = getSubtractingSequence(romanNumeral[i], romanNumeral[i + 1]);
                    if (substrResult == -1) {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
 
/*При вычитании допустимы только следующие
 * последовательности
 * IV (4), IX(9), XL(40), XC(90), CD(400), CM(900)
 */
int getSubtractingSequence(const char&left, const char&right) {
    int result;
    //cout << "getsub "<< left << " " <<  right << endl;
    result = getArabNumber(right) - getArabNumber(left);
    if (result == 900 || result == 400 || result == 90 || result == 40 || result == 9 || result == 4) {
        return result;
    }
    return -1;
}
 
/* Читаем строку. Проверяем на наличие цифры повторящейся
 * более трех раз подряд и корректность символа
 * Если все прошло успешно то функция заполняет массив и
 * возвращает true
 * !!! эта функция меняет значение размера массива
 */
bool getRomanNumeral(char romanNumeral[], int &maxSize) {
char ch;
int recurrenc = 1;
 
for (int i = 0; i < maxSize; ++i) { //идем по строке пока позволяет размер массива
    ch = cin.get();
    if (isCorrectLetter(ch) || ch == '\n') { //корректен ли символ
        if (i > 0) {
            if (romanNumeral[i - 1] == ch) { //если предыдущий символ равен текущему
                recurrenc++;
                if (recurrenc == 4) { //достигнут недопустимый предел повторений
                //cout << "UPS!";
                    cin.clear();
                    cin.ignore(1000, '\n');
                    return false;
                }
            } else {
                recurrenc = 1;
            }
        }
        if (ch == '\n') { //если достигнут конец строки
            romanNumeral[i] = '\0'; //то закрываем массмв char
            maxSize = i; //и выходим из цикла
        } else {
            romanNumeral[i] = ch;
        }
    } else {
        //cout << "UPS!";
        cin.clear();
        cin.ignore(1000, '\n');
        return false;
    }
    }
return true;
}
 
//return roman digit arabic equivalent
int getArabNumber(const char &rimNumber) {
 switch (rimNumber) {
 case 'I':
    return 1;
 case 'V':
    return 5;
 case 'X':
    return 10;
 case 'L':
    return 50;
 case 'C':
    return 100;
 case 'D':
    return 500;
 case 'M':
    return 1000;
 }
 return 0;
}
 
//check if provided roman digit is correct
bool isCorrectLetter(const char &letter) {
 const int size = 7;
 char mySymbols[size] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
 for (int i = 0; i < size; ++i) {
    if (letter == mySymbols[i]) {
        return true;
    }
 }
 return false;
}
alkagolik
 Аватар для alkagolik
1510 / 616 / 79
Регистрация: 15.07.2011
Сообщений: 3,552
15.12.2011, 02:49     задача на римскую систему счисления #14
C++
1
2
3
4
int getArabNumber(const char &rimNumber) {
 switch (rimNumber)
...
default: return 0;
страховка.
greeezz
272 / 165 / 4
Регистрация: 10.07.2011
Сообщений: 441
15.12.2011, 02:57     задача на римскую систему счисления #15
Цитата Сообщение от alkagolik Посмотреть сообщение
страховка.
спасибо, как то я даже и не подумал
Net_Wanderer
235 / 208 / 19
Регистрация: 08.06.2011
Сообщений: 467
15.12.2011, 15:09     задача на римскую систему счисления #16
вот на C, без дополнительных правил, т.е. позволяет написать одно число разными способами
может пригодится...
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <stdio.h>
 
int rtoa(int);
 
enum { NO, YES };
 
int main()
{
    int total; 
    int d;
    int next;
    int lim;
    int quit;
    int subtract;
    int buf;
    int c;
 
    lim = rtoa('M');
    total = buf = next = 0;
    subtract = quit = NO;
 
    while (quit == NO) {
        d = next;
        if ((c = getchar()) == '\n' || next == EOF) {
            next = 0;
            quit = YES;
        } else if ((next = rtoa(c)) < 0) {
            printf("incorrect symbol: %c\n", c);
            return 0;
        } else if (d == 0)
            continue;
 
        if (d >= next) {
            if (d > lim) {
                printf("incorrect order of the numerals\n");
                return 0;
            }
            lim = d;
            total += d - ((subtract == YES) ? buf : 0);
            subtract = NO;
            buf = 0;
        } else {
            if (subtract == YES) {
                printf("incorrect order of the numerals\n");
                return 0;
            }
            subtract = YES;
            buf = d;
        }
    }
    printf("arabic: %d\n", total);
    return 0;
}
    
int rtoa(int c)
{
    switch (c) {
    case 'I':
        return 1;
    case 'V':
        return 5;
    case 'X':
        return 10;
    case 'L':
        return 50;
    case 'C':
        return 100;
    case 'D':
        return 500;
    case 'M':
        return 1000;
    default:
        return -1;
    }
}
ПаЗитиФкА
3 / 3 / 0
Регистрация: 16.11.2011
Сообщений: 51
15.12.2011, 20:39  [ТС]     задача на римскую систему счисления #17
greeezz, спасибо большое за подробное объяснение! я сдала старые вариант - преподавательский тест программа прошла и ладно. с новым тоже разобралась, в целом все понятно
greeezz
272 / 165 / 4
Регистрация: 10.07.2011
Сообщений: 441
15.12.2011, 21:15     задача на римскую систему счисления #18
Цитата Сообщение от ПаЗитиФкА Посмотреть сообщение
преподавательский тест программа прошла и ладно
да тест преподавателя не главное. главное результат работы. даже если результат не правильный, то это тоже очень хороший результат - если разобраться почему он не правильный.

Не по теме:

к тому что преподователи не всегда мягко говоря правы...
Нам преподаватель на первой лекции по "Операционные системы Unix/Linux" заявил что Unix/Linux можно установить используя файловую систему NTFS.. .. после чего я понял что курс для меня потерян. Собственно так оно и получилось.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.12.2011, 21:28     задача на римскую систему счисления
Еще ссылки по теме:

Программа перевод чисел из арабской систеиы счисления в римскую C++
C++ Проверить корректность числа в заданной системе счисления и перевести в другую систему счисления
C++ Перевод чисел из файла в римскую систему счисления

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
prazuber
108 / 108 / 3
Регистрация: 29.04.2010
Сообщений: 240
15.12.2011, 21:28     задача на римскую систему счисления #19
До кучи, boost::spirit версия
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/*=============================================================================
    Copyright (c) 2001-2010 Joel de Guzman
 
    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at [url]http://www.boost.org/LICENSE_1_0.txt[/url])
=============================================================================*/
///////////////////////////////////////////////////////////////////////////////
//
//  A Roman Numerals Parser (demonstrating the symbol table). This is
//  discussed in the "Symbols" chapter in the Spirit User's Guide.
//
//  [ JDG August 22, 2002 ] spirit1
//  [ JDG March 13, 2007 ]  spirit2
//
///////////////////////////////////////////////////////////////////////////////
 
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
 
#include <iostream>
#include <string>
 
namespace client
{
    namespace qi = boost::spirit::qi;
    namespace ascii = boost::spirit::ascii;
 
    ///////////////////////////////////////////////////////////////////////////////
    //  Parse roman hundreds (100..900) numerals using the symbol table.
    //  Notice that the data associated with each slot is the parser's attribute
    //  (which is passed to attached semantic actions).
    ///////////////////////////////////////////////////////////////////////////////
    //[tutorial_roman_hundreds
    struct hundreds_ : qi::symbols<char, unsigned>
    {
        hundreds_()
        {
            add
                ("C"    , 100)
                ("CC"   , 200)
                ("CCC"  , 300)
                ("CD"   , 400)
                ("D"    , 500)
                ("DC"   , 600)
                ("DCC"  , 700)
                ("DCCC" , 800)
                ("CM"   , 900)
            ;
        }
 
    } hundreds;
    //]
 
    ///////////////////////////////////////////////////////////////////////////////
    //  Parse roman tens (10..90) numerals using the symbol table.
    ///////////////////////////////////////////////////////////////////////////////
    //[tutorial_roman_tens
    struct tens_ : qi::symbols<char, unsigned>
    {
        tens_()
        {
            add
                ("X"    , 10)
                ("XX"   , 20)
                ("XXX"  , 30)
                ("XL"   , 40)
                ("L"    , 50)
                ("LX"   , 60)
                ("LXX"  , 70)
                ("LXXX" , 80)
                ("XC"   , 90)
            ;
        }
 
    } tens;
    //]
 
    ///////////////////////////////////////////////////////////////////////////////
    //  Parse roman ones (1..9) numerals using the symbol table.
    ///////////////////////////////////////////////////////////////////////////////
    //[tutorial_roman_ones
    struct ones_ : qi::symbols<char, unsigned>
    {
        ones_()
        {
            add
                ("I"    , 1)
                ("II"   , 2)
                ("III"  , 3)
                ("IV"   , 4)
                ("V"    , 5)
                ("VI"   , 6)
                ("VII"  , 7)
                ("VIII" , 8)
                ("IX"   , 9)
            ;
        }
 
    } ones;
    //]
 
    ///////////////////////////////////////////////////////////////////////////////
    //  roman (numerals) grammar
    //
    //      Note the use of the || operator. The expression
    //      a || b reads match a or b and in sequence. Try
    //      defining the roman numerals grammar in YACC or
    //      PCCTS. Spirit rules! :-)
    ///////////////////////////////////////////////////////////////////////////////
    //[tutorial_roman_grammar
    template <typename Iterator>
    struct roman : qi::grammar<Iterator, unsigned()>
    {
        roman() : roman::base_type(start)
        {
            using qi::eps;
            using qi::lit;
            using qi::_val;
            using qi::_1;
            using ascii::char_;
 
            start = eps             [_val = 0] >>
                (
                    +lit('M')       [_val += 1000]
                    ||  hundreds    [_val += _1]
                    ||  tens        [_val += _1]
                    ||  ones        [_val += _1]
                )
            ;
        }
 
        qi::rule<Iterator, unsigned()> start;
    };
    //]
}
 
///////////////////////////////////////////////////////////////////////////////
//  Main program
///////////////////////////////////////////////////////////////////////////////
int
main()
{
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "\t\tRoman Numerals Parser\n\n";
    std::cout << "/////////////////////////////////////////////////////////\n\n";
    std::cout << "Type a Roman Numeral ...or [q or Q] to quit\n\n";
 
    typedef std::string::const_iterator iterator_type;
    typedef client::roman<iterator_type> roman;
 
    roman roman_parser; // Our grammar
 
    std::string str;
    unsigned result;
    while (std::getline(std::cin, str))
    {
        if (str.empty() || str[0] == 'q' || str[0] == 'Q')
            break;
 
        std::string::const_iterator iter = str.begin();
        std::string::const_iterator end = str.end();
        //[tutorial_roman_grammar_parse
        bool r = parse(iter, end, roman_parser, result);
 
        if (r && iter == end)
        {
            std::cout << "-------------------------\n";
            std::cout << "Parsing succeeded\n";
            std::cout << "result = " << result << std::endl;
            std::cout << "-------------------------\n";
        }
        else
        {
            std::string rest(iter, end);
            std::cout << "-------------------------\n";
            std::cout << "Parsing failed\n";
            std::cout << "stopped at: \": " << rest << "\"\n";
            std::cout << "-------------------------\n";
        }
        //]
    }
 
    std::cout << "Bye... :-) \n\n";
    return 0;
}
Yandex
Объявления
15.12.2011, 21:28     задача на римскую систему счисления
Ответ Создать тему
Опции темы

Текущее время: 23:54. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru