БлогNot. А для этого нужна числопредставлялка...

А для этого нужна числопредставлялка...

Интересная задачка - представить натуральное число N только с помощью цифры (или числа) D и четырёх арифметических операций над D, например, при N = 5, D = 4 имеем 5 = 4/4+4 ну или для N = 2019, D = 6, имеем 2019 = ((((6*6+6+6+6)*6+6+6)*6)*6+6+6+6)/6

Требуется, чтобы цепочка была наиболее короткой из возможных. Глубина поиска ограничена значением LIMIT.

Вот небольшой класс, решающий задачу с помощью рекурсивного поиска и тесты для него. Проверено в консоли Visual Studio 2015.

#include <iostream>
#include <sstream> 
#include <stack> 
#include <map> 
#include <algorithm>
#include <climits> 
using namespace std;

class singleDigit {
 int N, D, //число для разложения, число для представления
  LIMIT, minimum; //глубина поиска, минимальная глубина
 map <int, int> numbers; //рассматриваемые числа
 stack <char> operators; //операторы
public:
 singleDigit (int N = 0, int D = 0, int LIMIT=10) {
  this->N = N; this->D = D; this->LIMIT = minimum = LIMIT;
 }
 void minLevel (int total, int N, int D, int level) {
  if (total == N) {
   minimum = min(minimum, level);
   return;
  }
  if (level == minimum) return;
  if (total % D == 0) minLevel(total / D, N, D, level + 1);
  minLevel (total + D, N, D, level + 1);
  if (total - D > 0) minLevel(total - D, N, D, level + 1);
  minLevel (total * D, N, D, level + 1);
 }
 bool generate (int total, int N, int D, int level) {
  if (total == N) return true;
  if (level == minimum) return false;
  if (numbers.find(total) == numbers.end() || numbers.find(total)->second >= level) {
   numbers[total] = level;
   int divide = INT_MAX;
   if (total % D == 0) {
    divide = total / D;
    if (numbers.find(divide) == numbers.end()) numbers[divide] = level + 1;
   }
   int addition = total + D;
   if (numbers.find(addition) == numbers.end()) numbers[addition] = level + 1;
   int subtraction = INT_MAX;
   if (total - D > 0) {
    subtraction = total - D;
    if (numbers.find(subtraction) == numbers.end()) numbers[subtraction] = level + 1;
   }
   int multiply = total * D;
   if (numbers.find(multiply) == numbers.end()) numbers[multiply] = level + 1;
   if (divide != INT_MAX) if (generate(divide, N, D, level + 1)) {
    operators.push('/');
    return true;
   }
   if (generate(addition, N, D, level + 1)) {
    operators.push('+');
    return true;
   }
   if (subtraction != INT_MAX) if (generate(subtraction, N, D, level + 1)) {
    operators.push('-');
    return true;
   }
   if (generate(multiply, N, D, level + 1)) {
    operators.push('*');
    return true;
   }
  }
  return false;
 }
 string solve () {
  minLevel(D, N, D, 1);
  if (generate(D, N, D, 1)) {
   ostringstream num;
   num << D;
   string expression;
   if (!operators.empty()) {
    expression = num.str() + operators.top();
    operators.pop();
   }
   while (!operators.empty()) {
    if (operators.top() == '/' || operators.top() == '*')
     expression = "(" + expression + num.str() + ")" + operators.top();
    else
     expression = expression + num.str() + operators.top();
    operators.pop();
   }
   expression = expression + num.str();
   return expression;
  }
  else return "Solution not found for current search deep";
 }
};


int main() {
 singleDigit a0;
 cout << a0.solve() << endl;

 singleDigit a (5,4);
 cout << a.solve() << endl;

 singleDigit b (100, 7);
 cout << b.solve() << endl;

 singleDigit c(200, 9);
 cout << c.solve() << endl;
 
 singleDigit c1(200, 9, 12);
 cout << c1.solve() << endl;

 singleDigit d(2019, 6, 14);
 cout << d.solve() << endl;

 cin.get(); return 0;
}

Выдача этой программы:

0
4/4+4
(((7+7)*7)*7+7+7)/7
Solution not found for current search deep
(((9+9)*9+9+9+9+9)*9+9+9)/9
((((6*6+6+6+6)*6+6+6)*6)*6+6+6+6)/6

(d будет считаться подольше, чем остальное)

А вот цепочки для всех возможных пар значений (N,D) в пределах от 1 до 9 включительно:

1 1 1
1 2 2/2
1 3 3/3
1 4 4/4
1 5 5/5
1 6 6/6
1 7 7/7
1 8 8/8
1 9 9/9
2 1 1+1
2 2 2
2 3 (3+3)/3
2 4 (4+4)/4
2 5 (5+5)/5
2 6 (6+6)/6
2 7 (7+7)/7
2 8 (8+8)/8
2 9 (9+9)/9
3 1 1+1+1
3 2 2/2+2
3 3 3
3 4 (4+4+4)/4
3 5 (5+5+5)/5
3 6 (6+6+6)/6
3 7 (7+7+7)/7
3 8 (8+8+8)/8
3 9 (9+9+9)/9
4 1 1+1+1+1
4 2 2+2
4 3 3/3+3
4 4 4
4 5 (5*5-5)/5
4 6 (6+6+6+6)/6
4 7 (7+7+7+7)/7
4 8 (8+8+8+8)/8
4 9 (9+9+9+9)/9
5 1 1+1+1+1+1
5 2 2/2+2+2
5 3 (3+3)/3+3
5 4 4/4+4
5 5 5
5 6 (6*6-6)/6
5 7 (7*7-7-7)/7
5 8 (8+8+8+8+8)/8
5 9 (9+9+9+9+9)/9
6 1 1+1+1+1+1+1
6 2 2+2+2
6 3 3+3
6 4 (4+4)/4+4
6 5 5/5+5
6 6 6
6 7 (7*7-7)/7
6 8 (8*8-8-8)/8
6 9 (9*9-9-9-9)/9
7 1 1+1+1+1+1+1+1
7 2 2/2+2+2+2
7 3 3/3+3+3
7 4 (4+4+4)/4+4
7 5 (5+5)/5+5
7 6 6/6+6
7 7 7
7 8 (8*8-8)/8
7 9 (9*9-9-9)/9
8 1 1+1+1+1+1+1+1+1
8 2 (2+2)*2
8 3 (3+3)/3+3+3
8 4 4+4
8 5 (5+5+5)/5+5
8 6 (6+6)/6+6
8 7 7/7+7
8 8 8
8 9 (9*9-9)/9
9 1 1+1+1+1+1+1+1+1+1
9 2 2/2+2+2+2+2
9 3 3*3
9 4 4/4+4+4
9 5 ((5+5)*5-5)/5
9 6 (6+6+6)/6+6
9 7 (7+7)/7+7
9 8 8/8+8
9 9 9

Должно работать и для значений D, больших 9, например,

singleDigit a(100, 12, 12);
cout << a.solve() << endl;

выдаст верное

((12*12-12-12-12-12)*12+12+12+12+12)/12

но не фиг же :)

Числа - едва ли не единственное, что утешает
(С)
Доктор Зло зловеще намекает:
(((13+13+13+13)*13-13)*13+13+13+13)/13 = 666
((6+6+6)*6)*6+6+6+6 = 666

15.05.2019, 10:37 [1147 просмотров]


теги: c++ числа алгоритм

К этой статье пока нет комментариев, Ваш будет первым