Понедельник, 29.04.2024, 14:22
"I-School" - школа знаний XXI века
     In doing we learn
Главная | Регистрация | Вход Приветствую Вас Гость | RSS
Форма входа
Категории раздела
Пользователь ПК [0]
WEB-дизайн [0]
Программирование [18]
Корзина
Пользователь ПК [0]
WEB-дизайн [0]
Программирование [18]
Поиск
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Главная » Статьи » Информатика, программирование » Программирование

    Сокращение дробей для двоечников (Diofant)

    Задача решена на С++ в MS VS2013

    Можно, безусловно, сократить решение до 15 строк, но одной из целей было показать простейшее конструирование класса и работу со списком. 

    1. /*Сокращение дробей для двоечников
    2. Дробь 49/98 удивительна тем, что "сократив" одинаковую цифру 9 в числителе и знаменателе
    3. получаем 4/8, которая равна исходной дроби, то есть 49/98 = 4/8.
    4. Дроби вида 30/50 также обладают подобным свойством, но они тривиальные.
    5. Рассмотрим все нетривиальные положительные дроби, обладающие описанным свойством,
    6. в которых числитель меньше знаменателя (то есть дробь меньше единицы) и оба двузначные.
    7. Чему равна сумма знаменателей этих дробей?
    8. */
    9. #include <iostream>
    10. #include <list>
    11. //----------------------------------------------------------класс "Дробь"
    12. class Partition
    13. {
    14.     int nom;
    15.     int denom;
    16. public:
    17.     Partition();
    18.     Partition(int, int);
    19.     int Nom(){ return nom; }
    20.     int Denom(){ return denom; }
    21.     void Reset(int, int);
    22.     void Print();
    23. };
    24. Partition::Partition()
    25. {
    26.     nom = 1;
    27.     denom = 1;
    28. }
    29. Partition::Partition(int _nom, int _denom)
    30. {
    31.     nom = _nom;
    32.     denom = _denom;
    33. }
    34. void Partition::Reset(int _nom, int _denom)
    35. {
    36.     nom = _nom;
    37.     denom = _denom;
    38. }
    39. void Partition::Print()
    40. {
    41.     std::cout << nom << '/' << denom <<"\n";
    42. }
    43. //-------------------------------------------------- функции для решения задачи
    44. //------------------------------------сокращение согласно условию
    45. bool Simplify(Partition &p, Partition &s)
    46. {
    47.     int a = p.Nom()/10;
    48.     int b = p.Nom() - 10 * a;
    49.     int c = p.Denom() / 10;
    50.     int d = p.Denom() - 10 * c;
    51.     //тривиальные дроби не сокращаем
    52.     if (b == d && d == 0)
    53.         return false;
    54.     //в остальных случаях - ищем одинаковые цифры
    55.     //если находим - "сокращаем"
    56.     if (a == c)
    57.     {
    58.         s.Reset(b, d);
    59.         return true;
    60.     }
    61.     if (a == d)
    62.     {
    63.         s.Reset(b, c);
    64.         return true;
    65.     }
    66.     if (b == c)
    67.     {
    68.         s.Reset(a, d);
    69.         return true;
    70.     }
    71.     if (b == d)
    72.     {
    73.         s.Reset(a, c);
    74.         return true;
    75.     }
    76.     //одинаковых цифр не нашлось
    77.     return false;
    78. }
    79. //-----------------------------проверка двух дробей на равенство
    80. bool Equal(Partition &p, Partition &s)
    81. {
    82.     return p.Nom()*s.Denom() == s.Nom()*p.Denom();
    83. }
    84. //------------------------------------------------------решение
    85. void Solvation()
    86. {
    87.     //список для хранения найденных дробей
    88.     std::list<Partition> wanted;
    89.     //перебор всех двузначных правильных сократимых дробей
    90.     //OPTIM дробь сократима, значит числитель не больше половины знаменателя
    91.     for (int denom = 20; denom <= 99; denom++)
    92.         for (int nom = 10; nom <= denom/2; nom++)
    93.         {
    94.             Partition p(nom, denom);
    95.             Partition s;
    96.             if (Simplify(p, s))
    97.                 if (Equal(p, s))
    98.                     wanted.push_back(p);
    99.         }
    100.     //сумма знаменателей найденных дробей
    101.     int sum = 0;
    102.     
    103.     //вывод результатов
    104.     for (std::list<Partition>::iterator it = wanted.begin(); it != wanted.end(); it++)
    105.     {
    106.         (*it).Print();
    107.         sum += (*it).Denom();
    108.     }
    109.     std::cout << "SUM = " << sum;
    110. }
    111. //--------------------------------------------------------------------MAIN
    112. int main()
    113. {
    114.     Solvation();
    115.     std::cin.get();
    116.     return 0;
    117. }
    118. //--------------------------------------------------------------------------

    Результат:

    Таким образом, мы видим, что существует 4 таких нетривиальных дроби.

    Эти дроби могут послужить хорошим примером того, как неправильные действия приводят к правильному решению. 

    Учитывая, что всего правильных дробей с двузначным числителем и знаменателем

    N = 1+2+3+...+89 = 45*89 = 4005,

    и только в четырех случаях нам "повезет", вероятность везения

    р = 4 / 4005 ~ 1/1000

    Тем не менее, лучше бы она была нулевая ;)

    Категория: Программирование | Добавил: IrineK (06.07.2016)
    Просмотров: 1298 | Теги: класс дробь, итератор, список объектов | Рейтинг: 0.0/0
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Copyright MyCorp © 2024
    Конструктор сайтов - uCoz