Задача решена на С++ в MS VS2013
Можно, безусловно, сократить решение до 15 строк, но одной из целей было показать простейшее конструирование класса и работу со списком.
- #include <iostream>
- #include <list>
- class Partition
- {
- int nom;
- int denom;
- public:
- Partition();
- Partition(int, int);
- int Nom(){ return nom; }
- int Denom(){ return denom; }
- void Reset(int, int);
- void Print();
- };
- Partition::Partition()
- {
- nom = 1;
- denom = 1;
- }
- Partition::Partition(int _nom, int _denom)
- {
- nom = _nom;
- denom = _denom;
- }
- void Partition::Reset(int _nom, int _denom)
- {
- nom = _nom;
- denom = _denom;
- }
- void Partition::Print()
- {
- std::cout << nom << '/' << denom <<"\n";
- }
- bool Simplify(Partition &p, Partition &s)
- {
- int a = p.Nom()/10;
- int b = p.Nom() - 10 * a;
- int c = p.Denom() / 10;
- int d = p.Denom() - 10 * c;
-
- if (b == d && d == 0)
- return false;
-
-
- if (a == c)
- {
- s.Reset(b, d);
- return true;
- }
- if (a == d)
- {
- s.Reset(b, c);
- return true;
- }
- if (b == c)
- {
- s.Reset(a, d);
- return true;
- }
- if (b == d)
- {
- s.Reset(a, c);
- return true;
- }
-
- return false;
- }
- bool Equal(Partition &p, Partition &s)
- {
- return p.Nom()*s.Denom() == s.Nom()*p.Denom();
- }
- void Solvation()
- {
-
- std::list<Partition> wanted;
-
-
- for (int denom = 20; denom <= 99; denom++)
- for (int nom = 10; nom <= denom/2; nom++)
- {
- Partition p(nom, denom);
- Partition s;
- if (Simplify(p, s))
- if (Equal(p, s))
- wanted.push_back(p);
- }
-
- int sum = 0;
-
-
- for (std::list<Partition>::iterator it = wanted.begin(); it != wanted.end(); it++)
- {
- (*it).Print();
- sum += (*it).Denom();
- }
- std::cout << "SUM = " << sum;
- }
- int main()
- {
- Solvation();
- std::cin.get();
- return 0;
- }
/*Сокращение дробей для двоечников
Дробь 49/98 удивительна тем, что "сократив" одинаковую цифру 9 в числителе и знаменателе
получаем 4/8, которая равна исходной дроби, то есть 49/98 = 4/8.
Дроби вида 30/50 также обладают подобным свойством, но они тривиальные.
Рассмотрим все нетривиальные положительные дроби, обладающие описанным свойством,
в которых числитель меньше знаменателя (то есть дробь меньше единицы) и оба двузначные.
Чему равна сумма знаменателей этих дробей?
*/
#include <iostream>
#include <list>
//----------------------------------------------------------класс "Дробь"
class Partition
{
int nom;
int denom;
public:
Partition();
Partition(int, int);
int Nom(){ return nom; }
int Denom(){ return denom; }
void Reset(int, int);
void Print();
};
Partition::Partition()
{
nom = 1;
denom = 1;
}
Partition::Partition(int _nom, int _denom)
{
nom = _nom;
denom = _denom;
}
void Partition::Reset(int _nom, int _denom)
{
nom = _nom;
denom = _denom;
}
void Partition::Print()
{
std::cout << nom << '/' << denom <<"\n";
}
//-------------------------------------------------- функции для решения задачи
//------------------------------------сокращение согласно условию
bool Simplify(Partition &p, Partition &s)
{
int a = p.Nom()/10;
int b = p.Nom() - 10 * a;
int c = p.Denom() / 10;
int d = p.Denom() - 10 * c;
//тривиальные дроби не сокращаем
if (b == d && d == 0)
return false;
//в остальных случаях - ищем одинаковые цифры
//если находим - "сокращаем"
if (a == c)
{
s.Reset(b, d);
return true;
}
if (a == d)
{
s.Reset(b, c);
return true;
}
if (b == c)
{
s.Reset(a, d);
return true;
}
if (b == d)
{
s.Reset(a, c);
return true;
}
//одинаковых цифр не нашлось
return false;
}
//-----------------------------проверка двух дробей на равенство
bool Equal(Partition &p, Partition &s)
{
return p.Nom()*s.Denom() == s.Nom()*p.Denom();
}
//------------------------------------------------------решение
void Solvation()
{
//список для хранения найденных дробей
std::list<Partition> wanted;
//перебор всех двузначных правильных сократимых дробей
//OPTIM дробь сократима, значит числитель не больше половины знаменателя
for (int denom = 20; denom <= 99; denom++)
for (int nom = 10; nom <= denom/2; nom++)
{
Partition p(nom, denom);
Partition s;
if (Simplify(p, s))
if (Equal(p, s))
wanted.push_back(p);
}
//сумма знаменателей найденных дробей
int sum = 0;
//вывод результатов
for (std::list<Partition>::iterator it = wanted.begin(); it != wanted.end(); it++)
{
(*it).Print();
sum += (*it).Denom();
}
std::cout << "SUM = " << sum;
}
//--------------------------------------------------------------------MAIN
int main()
{
Solvation();
std::cin.get();
return 0;
}
//--------------------------------------------------------------------------
Результат:
![](http://allproblems.ucoz.ru/problems/partitions_res.png)
Таким образом, мы видим, что существует 4 таких нетривиальных дроби.
Эти дроби могут послужить хорошим примером того, как неправильные действия приводят к правильному решению.
Учитывая, что всего правильных дробей с двузначным числителем и знаменателем
N = 1+2+3+...+89 = 45*89 = 4005,
и только в четырех случаях нам "повезет", вероятность везения
р = 4 / 4005 ~ 1/1000
Тем не менее, лучше бы она была нулевая ;)
|