LINUX.ORG.RU

Яблоконь LOR Codewars (продолжение): задача на комбинаторику или сраный Сбер теперь FAANG

 ,


1

3

Сраный Сбер от которого пахнет могилами как и от значительной части его вкладчиц поверил в себя и теперь ищет лучших из лучших, наивно полагая, что кому-то эта срань сдалась:

Напишите, пожалуйста, программу на любом языке программирования, которая поместит + (2+3), - (3-2), или ничего ( ) в промежутках между цифрами от 9 до 0 (в таком порядке) так, чтобы в результате получилось 200. Например: 98+76-5+43-2-10=200.

Кто хочет себя испытать в решении тру-задач для формошлепов (которые в работе применяются не реже чем никогда)?

Ну и как полагается решение:

Показать все что скрыто

from itertools import product

# Целевая сумма
target = 200

# Цифры от 9 до 0
digits = '9876543210'

# Все возможные комбинации из '+', '-', и пустой строки
operators = ['+', '-', '']
combinations = product(operators, repeat=len(digits)-1)

# Функция для создания выражения из комбинации операторов
def create_expression(digits, ops):
    expr = digits[0]
    for d, op in zip(digits[1:], ops):
        expr += op + d
    return expr

# Проход по всем комбинациям и проверка результата
for ops in combinations:
    expr = create_expression(digits, ops)
    try:
        if eval(expr) == target:
            print(f'{expr} = {target}')
    except ZeroDivisionError:
        continue

Какой язык победит в сией битве? На каком решение будем самым коротким и лаконичным?

Тема посвещается памяти @kompspec’а, нашедшего работу за 20 рублей в час, и поэтому прекратившему посещать сий сайт. Любим пони, скайрим.

которая поместит + (2+3), - (3-2), или ничего ( ) в промежутках между цифрами от 9 до 0 (в таком порядке) так, чтобы в результате получилось 200. Например: 98+76-5+43-2-10=200.

КАВО? Во-первых 2+3 не «в таком порядке», наверное таки 3+2. Во-вторых почему собственно 3+2, 3-2 заслуживают отдельного упоминания? Они всё равно встретятся «в таком порядке».

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от rtxtxtrx

Я понял, 3+2 и т.д. это просто для примера. Этим ушлёпкам нужно для начала научиться формулировать что они хотят. Так-то задача для школьников.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)

Задача вроде очень классическая. От сбера ожидал чего сложнее. Задача на маски. В данном случае получаются троичные.

Перебираем все N-значные числа в троичной системе счисления, просто добавляя к первому разряду единицу и перенося разряд до тех пор, пока надо его переносить.

Будем идти по выражению и смотреть соответствующий бит маски.

  1. Если это бит «нет знака», то приклеиваем в конец регистра новую чиселку.

  2. Если это бит знака, то добавляем регистр со знаком к сумме, и инициализируем регистр и его знак заново.

Настоящий код на компьютере писать было впадлу, но по всевдокоду получается что-то такое.

Задача была бы намного интереснее, если бы в ограничениях было либо больше знаков, либо больше чисел, не от 9 до 0, а от Z до 0.

Тогда, наверное, надо было бы думать какое-нибудь ДП. Я их, кстати, почти не умею придумывать.

енум Операция {
   ПЛЮС = 0
   МИНУС = 1
   ПРОЧЕРК = 2
}
НОВЫЙ_РАЗРЯД = 3

МАКС_ЦИФРА = 9
RES        = 200
ЗНАКОВ     = МАКС_ЦИФРА - 1

маска = массив(0, ЗНАКОВ + 1)

пока маска.конец == 0:

  сумма = 0
  регистр = МАКС_ЦИФРА
  регистр_знак = 1
  текущая_цифра = МАКС_ЦИФРА

  # считаем сумму по маске
  для номер_знака от 0 до ЗНАКОВ:
    текущая_цифра -= 1
    знак = маска[номер_знака]
    если знак = ПРОЧЕРК:
      регистр *= 10
      регистр += текущая_цифра
    иначе:
      сумма += регистр * регистр_знак
      регистр = текущая_цифра
      если знак = ПЛЮС:
        регистр_знак = 1
      иначе:
        регистр_знак = -1

  # добиваем последнее число
  сумма += регистр * регистр_знак

  # если сумма нужная, вывести
  Если сумма = RES:
    текущая_цифра = МАКС_ЦИФРА
    вывод(текущая_цифра)
    для номер_знака от 0 до ЗНАКОВ:     
      текущая_цифра -= 1
      знак = маска[номер_знака]
      Если знак ПЛЮС:
        вывод(+)
      если знак МИНУС:
        вывод(-)
      вывод(текущая_цифра)
    вывод_нов_строка()
    
  # перейти к новой маске
  маска[0] += 1
  разряд = 0
  пока (разряд < маска.размер) И (маска[разряд] == НОВЫЙ_РАЗРЯД):
      маска[разряд] = 0
      маска[разряд + 1] += 1
      разряд += 1
witaway
()

Когда хрюшам делать нефиг, они придумывают спецолимпиады, чтобы было много интервью и мало проходящих их кандидатов. При этом, по традиции, вместе с водой выплескивают и младенца, ибо тех, кто пошел на такую спецолимпиаду и не прошел, но при этом является неплохим специалистом senior+, меньше, чем других senior+, которые из уважения к себе на такое говно не ходят в принципе.

Единственный способ в такие заведения попасть, минуя спецолимпиады - реферал изнутри, причем не от старшего помощника мдашего уборщика, а минимум от руководителя департамента.

pekmop1024 ★★★★★
()

У меня так получилось.

const expectedValue = 200;

const digits = ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0'];
const operations = ['', '+', '-'];
const permutation = new Uint8Array(digits.length - 1).fill(0);
do {
  const expressionChars = [];
  for (let i = 0; i < digits.length - 1; i++) {
    expressionChars.push(digits[i]);
    expressionChars.push(operations[permutation[i]]);
  }
  expressionChars.push(digits[digits.length - 1]);
  const expressionString = expressionChars.join('');
  const expressionValue = eval(expressionString);
  if (expressionValue === expectedValue) console.log(expressionString);
} while (nextPermutation(permutation, operations.length));


function nextPermutation(permutation, cardinality) {
  let i = permutation.length - 1;
  while (i >= 0 && permutation[i] === cardinality - 1) {
    permutation[i] = 0;
    i--;
  }
  if (i < 0) return false;
  permutation[i]++;
  return true;
}
vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)
Ответ на: комментарий от anonymous

Рабочий вроде:

~   
❯ ipython
Python 3.12.4 (main, Jun  7 2024, 06:33:07) [GCC 14.1.1 20240522]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.26.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: def find_expression_with_expected_value(expected_value):
   ...:     digits = ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0']
   ...:     operations = ['', '+', '-']
   ...:     permutation = [0] * (len(digits) - 1)
   ...: 
   ...:     def next_permutation(permutation, cardinality):
   ...:         i = len(permutation) - 1
   ...:         while i >= 0 and permutation[i] == cardinality - 1:
   ...:             permutation[i] = 0
   ...:             i -= 1
   ...:         if i < 0:
   ...:             return False
   ...:         permutation[i] += 1
   ...:         return True
   ...: 
   ...:     results = []
   ...: 
   ...:     while True:
   ...:         expression_chars = []
   ...:         for i in range(len(digits) - 1):
   ...:             expression_chars.append(digits[i])
   ...:             expression_chars.append(operations[permutation[i]])
   ...:         expression_chars.append(digits[-1])
   ...:         expression_string = ''.join(expression_chars)
   ...:         expression_value = eval(expression_string)
   ...:         if expression_value == expected_value:
   ...:             results.append(expression_string)
   ...:         if not next_permutation(permutation, len(operations)):
   ...:             break
   ...: 
   ...:     return results
   ...: 
   ...: # Пример использования:
   ...: expected_value = 200
   ...: expressions = find_expression_with_expected_value(expected_value)
   ...: for expr in expressions:
   ...:     print(expr)
   ...: 
98+76-5+43-2-10
98-7+65+43+2-1+0
98-7+65+43+2-1-0
9-8+7-6-5-4-3+210
9-8-7-6-5+4+3+210

Но это не я, а чертгпт переписал на петухон

rtxtxtrx ★★
() автор топика
Последнее исправление: rtxtxtrx (всего исправлений: 2)
Ответ на: комментарий от rtxtxtrx

Да, GPT конечно силён. Засунул ему прям в исходной формулировке задачу, он мне выплюнул:

from itertools import product

def evaluate_expression(expression):
    try:
        return eval(expression)
    except:
        return None

def find_expression():
    digits = "9876543210"
    operations = ['+', '-', '']
    target = 200
    
    for ops in product(operations, repeat=len(digits)-1):
        expression = "".join(d + o for d, o in zip(digits, ops + ('',)))
        if evaluate_expression(expression) == target:
            return expression
    return None

result = find_expression()
if result:
    print(f"Expression found: {result} = 200")
else:
    print("No expression found that equals 200.")

Работает.

vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)
Ответ на: комментарий от rtxtxtrx

Я: а теперь сократи этот код используя itertools ЧмоGPT: Конечно, вот сокращенная версия кода, использующая itertools:

import itertools

def find_expression_with_expected_value(expected_value):
    digits = ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0']
    operations = ['', '+', '-']
    
    results = []

    for ops in itertools.product(operations, repeat=len(digits) - 1):
        expression_chars = [digits[0]]
        for digit, op in zip(digits[1:], ops):
            expression_chars.append(op)
            expression_chars.append(digit)
        expression_string = ''.join(expression_chars)
        expression_value = eval(expression_string)
        if expression_value == expected_value:
            results.append(expression_string)

    return results

# Пример использования:
expected_value = 200
expressions = find_expression_with_expected_value(expected_value)
for expr in expressions:
    print(expr)

В этой версии кода используется itertools.product для генерации всех возможных комбинаций операций, что значительно сокращает объем кода и делает его более читабельным.

rtxtxtrx ★★
() автор топика
Ответ на: комментарий от rtxtxtrx

Ничёси он там всё поменял. Первоисточник не уважает совсем. Евалы это некрасиво. Я бы за них задачу не засчитывал. 🙂

witaway
()
Последнее исправление: witaway (всего исправлений: 1)
Ответ на: комментарий от vbr

Да нет, к компьютеру было подходить ленотно, накидал псевдокод. Там дубовая императивщина, должно в любой язык транслироваться 1 к 1.

witaway
()
Последнее исправление: witaway (всего исправлений: 2)
Ответ на: комментарий от witaway

А чем тебе евалы не нравятся? Увольняют по профнепригодности при использовании eval’ов для парсинга json, приходящего от юзверя, в иных случаях ненависть к ним - разновидность шизотипии

rtxtxtrx ★★
() автор топика
Последнее исправление: rtxtxtrx (всего исправлений: 1)
Ответ на: комментарий от rtxtxtrx

пропущено 9-87+6+5+43+210

Удачно, как говорится, кодить с нейронками (смайлик клоун)

expr = ['9']


def rec(digit, cs, total):
    global expr
    if digit == 0:
        if total == 200:
            yield ''.join(expr)
        return

    expr += [str(digit - 1)]
    yield from rec(digit - 1, cs * 10 + digit - 1, total + cs * 9 + digit - 1)
    expr.pop()
    expr += ['+', str(digit - 1)]
    yield from rec(digit - 1, digit - 1, total + digit - 1)
    expr.pop()
    expr.pop()
    expr += ['-', str(digit - 1)]
    yield from rec(digit - 1, 1 - digit, total - digit + 1)
    expr.pop()
    expr.pop()


for ans in rec(9, 9, 9):
    print(ans)

PS лол, это у меня ответ неправильный. Ну клоун, получается :))

Lrrr ★★★★★
()
Последнее исправление: Lrrr (всего исправлений: 1)
Ответ на: комментарий от Lrrr

зато нестандартно. надо с асинками написать или использовать возможность генераторов отправлять сообщения

rtxtxtrx ★★
() автор топика
Последнее исправление: rtxtxtrx (всего исправлений: 1)
Ответ на: комментарий от rtxtxtrx

самый обычный рекурсивный перебор на питоне.

Который еще и могут завалить на собесе, потому что на рекурсию требуется не константное количество памяти, которое может кончиться с переполнением стека.

def rec(digit, cs, total):
    global expr

    if digit == 0:
        if total == 200:
            yield ''.join(expr)
        return

    expr += [str(digit - 1)]
    cs2 = cs * 10 + digit - 1
    if cs < 0:
        cs2 = cs * 10 + 1 - digit
    yield from rec(digit - 1, cs2, total - cs + cs2)
    expr.pop()
    expr += ['+', str(digit - 1)]
    yield from rec(digit - 1, digit - 1, total + digit - 1)
    expr.pop()
    expr.pop()
    expr += ['-', str(digit - 1)]
    yield from rec(digit - 1, 1 - digit, total - digit + 1)
    expr.pop()
    expr.pop()

вот так правильно, кстати

Lrrr ★★★★★
()
Ответ на: комментарий от rtxtxtrx

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

  1. А если бы ввод поступал от пользователя, а не генерировался автоматически, собеседуемый это тоже отправил в евал? А учёл ли бы он потенциальные проблемы с безопасностью? Сказал ли он что-то по этому поводу?
  2. Может ли он решить ту же самую задачу своими силами? Если да, почему не хочет продемонстрировать?

Так-то у тебя могут и попросить исполнить какое-нибудь арифметическое выражение, с евалом делается в одну строку — и всё равно нещитово.

witaway
()
Ответ на: комментарий от witaway

мне оно уже не грозит. у меня в резюме вообще написано чтобы яндекс, вк, банки шли куда подальше. а это конкретное тестовое задание в сбер клауд или клауд.ру (не помню как точно) - распильный проект от сбера по импортозамещению облаков. обязаловка очередная, где госкомпании будут покупать услуги у госкомпании по завышенным ценнам чтобы побольше бабла своровать через схемы с консалтинговыми, юридическими, финансовыми и прочими услугами. я осуждаю такое

rtxtxtrx ★★
() автор топика
digits="9876543210"
ops="+,-,' '"
result="200"

len=$((${#digits}-1))

exp(){
    echo \
${1:0:1}${2:0:1}\
${1:1:1}${2:1:1}\
${1:2:1}${2:2:1}\
${1:3:1}${2:3:1}\
${1:4:1}${2:4:1}\
${1:5:1}${2:5:1}\
${1:6:1}${2:6:1}\
${1:7:1}${2:7:1}\
${1:8:1}${2:8:1}\
${1:9:1}${2:9:1}\
| tr -d ' '
}

s=$(printf "%0.s{$ops}" $(seq $len))
eval "a=($(eval "printf '\"%s\"\n' $s"))"
for s in "${a[@]}"
do
    e=$(exp "$digits" "$s")
    eval r=$(( $e ))
    if [[ $r == $result ]]
    then
        echo $e=$result
    fi
done
time bash cartesian.sh 
9-8+7-6-5-4-3+210=200
9-8-7-6-5+4+3+210=200
98+76-5+43-2-10=200
98-7+65+43+2-1+0=200
98-7+65+43+2-1-0=200

real	1m45,681s
user	0m47,510s
sys	1m13,866s

anonymous
()
const ND:usize = 9;

#[derive(Debug, Copy, Clone)]
enum Op {
    Plus,
    Minus,
    Void,
}
impl Op {
    fn next_op(&mut self, pos: usize, iter: usize) {
        if iter % 3usize.pow(pos as u32) == 0 {
            *self = match self {
                Op::Void => Op::Minus,
                Op::Minus => Op::Plus,
                Op::Plus => Op::Void,
            }
        }
    }
}
fn calc_expr(ops: &[Op]) -> isize {
    let (mut sum, mut num, mut sign) = (0, ND as isize, 1);
    for (di, op) in ops.into_iter().enumerate() {
        let nxt_dig = (ND-1-di) as isize; 
        match op {
            Op::Void => num = num*10 + nxt_dig,
            Op::Plus => {
                sum += num * sign;
                num = nxt_dig; 
                sign = 1;
            }
            Op::Minus => {
                sum += num * sign;
                num = nxt_dig;
                sign = -1;
            }
        };
    }
    sum + num*sign
}
fn expr_to_str(ops:&[Op])->String {
    let mut s = "9".to_string();
    for (di, op) in ops.into_iter().enumerate() {
        match op {
            Op::Minus => s.push('-'),
            Op::Plus => s.push('+'),
            _ => ()
        }
        s.push(char::from_digit((ND-1-di) as u32, 10).unwrap());
    }
    s
}
fn main() {
    let target = 200;
    let mut ops = [Op::Void; ND];
    for i in 0..3usize.pow(ND as u32) { 
        if calc_expr(&ops) == target {
            println!("{}={target}", expr_to_str(&ops));
        }
        for p in 0..ND {
            ops[p].next_op(p, i);
        }
    }
}
cargo r -r
98-7+65+43+2-1-0=200
98-7+65+43+2-1+0=200
98+76-5+43-2-10=200
9-8+7-6-5-4-3+210=200
9-8-7-6-5+4+3+210=200

hyperfine --runs 500 -N  ./target/release/lortst
Benchmark 1: ./target/release/lortst
  Time (mean ± σ):       2.8 ms ±   1.1 ms    [User: 1.5 ms, System: 1.1 ms]
  Range (min … max):     1.2 ms …   4.4 ms    500 runs
zurg
()
Последнее исправление: zurg (всего исправлений: 1)
Ответ на: комментарий от pekmop1024

из уважения к себе

Уважение к себе быстро делится на ноль сразу как жизнь заставит.

Единственный способ в такие заведения попасть, минуя спецолимпиады

За пределами СНГ таких способов не существует. Реферал максимум даст тебе шанс попасть на эту спецолимпиаду вне очереди из индокетайских мокак.

PhD
()
Ответ на: комментарий от PhD

Уважение к себе быстро делится на ноль сразу как жизнь заставит.

Значит его и не было.

За пределами СНГ таких способов не существует. Реферал максимум даст тебе шанс попасть на эту спецолимпиаду вне очереди из индокетайских мокак.

Не совсем так, но анонимным теоретикам виднее…

pekmop1024 ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Хоспади ну я и дебил (смотреть в удалённых)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

struct list
{
    char * data;
    struct list * next;
};

int main(int argc, char ** argv)
{
    char     input[]   = "9876543210";
    int      need_found = 200;
    uint8_t  input_len = sizeof(input);
    char     reuse[input_len*2];
    uint16_t limit  = 0x1FF;
    uint64_t reuse_cnt = 0;
    struct list * l = malloc(sizeof(struct list));
    struct list * last = l;
    for (int skip = 0; skip != limit; ++skip )
    {
        for( int opers=limit ;opers != -1; opers--)
        {
            for (int i = 0; i != input_len;i++)
            {
               reuse[reuse_cnt++] = input[i];
               if( i+2 != input_len && ((skip >> i) & 1))
               {
                  reuse[reuse_cnt++] = ((opers >> i) & 1) ? '-' : '+';
               }
            }
            int64_t on[] = {0,0,0,0,0,0,0,0,0,0,0};
            char *  fmt  =  "%li%li%li%li%li%li%li%li%li%li";
            long n = sscanf(reuse, fmt, &on[0],&on[1],&on[2],
                                        &on[3],&on[4],&on[5],
                                        &on[6],&on[7],&on[8],
                                                      &on[9]);

            int64_t result = 0;
            for (int x = 0; x < n; x++)
            {
                 result+=on[x];
            }
            if(result == need_found)
            {
               int found = 0;
               struct list * ln = l;
               while(ln)
               {
                  if(ln->data)
                  {
                      if(strcmp(ln->data,reuse) == 0)
                      {
                         found=1;
                         break;
                      }
                  }
                  ln = ln->next;
               }

               if(found==0)
               {
                  last->next = malloc(sizeof(struct list));
                  last->next->data = malloc(strlen(reuse)+1);
                  memcpy(last->next->data,reuse,strlen(reuse)+1);
                  last=last->next;
               }
            }

            memset(reuse,0,sizeof(reuse));
            reuse_cnt=0;
         }
    }
    while(l)
    {
       if(l->data)
       {
           printf("%-2zu: %-17s == 200\n",++reuse_cnt,l->data);
           free(l->data);
       }
       last = l;
       l = l->next;
       free(last);
    }
    return 0;
}
dron@gnu:~/Рабочий-стол$ gcc -Wall -Werror test.c && ./a.out 
1 : 9-8+7-6-5-4-3+210 == 200
2 : 9-8-7-6-5+4+3+210 == 200
3 : 98+76-5+43-2-10   == 200
4 : 98-7+65+43+2-1-0  == 200
5 : 98-7+65+43+2-1+0  == 200
dron@gnu:~/Рабочий-стол$ 

С меня хватит! Сваливаю на винду и буду в гамбасе мышкой программировать и формы рисовать! Или визуал бейски или как там его зобыл. @rtxtxtrx эта задача была из разряда решить за 10 минут на бумажке да? Если да, тогда я её в 144 раза дольше решал :D

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)
Ответ на: комментарий от LINUX-ORG-RU

Извините, а что у вас там происходит? О_О

Вижу много каких-то аллокаций, кажись, связный список, какие-то проверки на дубликаты, битовая арифметика.

А в чём суть?

witaway
()
Последнее исправление: witaway (всего исправлений: 1)
Ответ на: комментарий от witaway

В надмозге :D + и - это просто все варианты последовательной инкрементации чиселка, битовые операции для получения бита, бит задаёт операцию, но операции никакой кроме сложения нет, на деле бит задаёт это положительно число или отрицательное, затем ещё чиселко, его биты задают будет тут операция или будет следующий символ склеен в число. После sscanf распознаёт +n и -n как положительные и отрицательные числа так что нет разницы в итоге между 5 + 5 - 3 и 5 + 5 + -3 далее идёт вычисление если результат == 200 и его нет в списке результатов (list) он добавляется в лист, если есть пропускается. В конце лист разворачивается выводя своё содержимое и тут же самоочищается.

Вот такой вот дурдом :D

А в чём суть?

Сути нет, есть только путь! :D Пусть плохенькое, зато своё :)

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Битмаски в битмасках, что ли?

  1. Внешняя = плюс / минус.

  2. Внутренняя = всё же выполнить операцию / склеить?

Тогда я, кажется, понимаю, зачем у вас проверки существования и откуда взялись дубли. Вообще, занятно получилось. :)

Кстати, если вы не хотите делать две вложенные битмаски, как оно у вас, и не хотите делать троичные маски, как оно у меня, могу предложить компромисс, оно только что в голову пришло:

Сделайте одну общую битмаску удвоенного размера, но при этом по четным битам определяйте, наличие операции, а по нечетным знак операции.

Получится в сути то же самое, что и у вас, но покороче.

А ещё, наверное, можно пойти дальше и избавиться от дублей. Но тогда надо пропускать маски.

Пропускать, наверное, такие, в которых при хоть одном бите операции = склеить, соответствующий бит знака ≠ 0.

Получаются как будто четверичные маски, которые на самом деле вырождаются в неявные троичные. Плюс одна неиспользуемая комбинация на каждые 2 бита бонусом, как бэ с заделом на будущее :D

witaway
()
Последнее исправление: witaway (всего исправлений: 7)
Ответ на: комментарий от witaway

Битмаски в битмасках, что ли?

Ага

Сделайте одну общую битмаску удвоенного размера

Ну там отличия копеешные будут. Но, да можно чередовать, а можно просто сначала кусок одних бит потом кусок других бит. Оставим это следующим господам. У меня вообще с комбинациями очень плохо, мозг клинит из недавнего Как понять что ты тупой?

А пока, а пока ррррандом р-р-р-руулит :D

local loadstring = loadstring or load;
local res = { }
local opr = {'+','-'}
local r = function(data,buf)
    if not buf[1] then
       return '',false
    end
    if data[#data] ~= '+' and data[#data] ~= '-'
       and #data    >  0  and math.random(0,1) == 0 then
       return opr[math.random(1,2)],true
    end
    return table.remove(buf,1),true
end
while(true) do
    local out = {}
    local buf = {9,8,7,6,5,4,3,2,1,0}
    local doi = true
    while(doi) do
        out[#out+1],doi = r(out,buf)
    end
    local static = table.concat(out)
    if loadstring('return '..static)() == 200 then
       if not res[static] then
          res[static] = true
          print(static..' == 200');
       end
    end
end
dron@gnu:~/Рабочий-стол$ lua test.lua 
9-8-7-6-5+4+3+210 == 200
98-7+65+43+2-1+0 == 200
98+76-5+43-2-10 == 200
98-7+65+43+2-1-0 == 200
9-8+7-6-5-4-3+210 == 200
^C
LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Ну там отличия копеешные будут. Но, да можно чередовать, а можно просто сначала кусок одних бит потом кусок других бит. Оставим это следующим господам.

Вы, кстати, только что подкинули крутую идею!

Если биты не чередовать, а взять сначала кусок одних бит, а потом кусок других бит, можно будет очень красиво и быстро отфильтровывать лишние маски:

bool badmask = (mask >> N) & mask > 0;, при условии, что операции «склеить число» соответствует бит 1.

Ну, или если хочется, чтобы там был именно бит 0, можно добавить отрицание. Суть та же.

И тогда разница, всё же, получается ого-го!

P.s.

Если уж развивать эту тему, можно сделать примерно то же самое и в условиях чередующихся бит.

Тогда чётные и нечетные нужно менять местами.

bool badmask = mask & mask_swapped > 0;

Где

bool mask_swapped = ((mask & 0b101010...) >> 1) | ((mask & 0b010101...) << 1)

Итого

bool bad_mask = mask & (((mask & 0b101010...) >> 1) | ((mask & 0b010101...) << 1))) > 0

Но это уже совсем не красиво и не элегантно :)

witaway
()
Последнее исправление: witaway (всего исправлений: 3)
Ответ на: комментарий от witaway

Да, так будет короче и прикольнее и элегантнее =) Но время пол третьего, у меня ща последняя и единственная извилина в черепном горшке лопнет :D

Пусть другие тоже порезвятся. Вот было бы ещё условие изначально, уложится в 25 строк для интерпретируемых и 50 строк для компилируемых языков вот тогда дааа.

Так или иначе упаковываюсь в люльку и… хрррр, хрррр, пук, хрррр.

LINUX-ORG-RU ★★★★★
()

Вариация на тему декартово произведения, то есть полного рекурсивного перебора

DIGITS = {'9','8','7','6','5','4','3','2','1','0'}
OPS = {'+','-',''}
TARGET = 200

local eval = loadstring or load
local len = #DIGITS
local function bf(pos, expr)
  if pos > len then
    if eval("return " .. expr)() == TARGET then
      print(expr .. "=" .. TARGET)
    end
    return
  end
  for _, o in ipairs(OPS) do
    bf(pos + 1, expr .. o .. DIGITS[pos])
  end
end
bf(2, DIGITS[1])
$ lua bruteforce.lua 
9-8+7-6-5-4-3+210=200
9-8-7-6-5+4+3+210=200
98+76-5+43-2-10=200
98-7+65+43+2-1+0=200
98-7+65+43+2-1-0=200

можно добавить операций: умножение ‘*’ и деление ‘/’

anonymous
()

Вот ещё один вариант родился, мне нравится. Есть в этом какое-то благородное безумие.

function f(n, s) {
  if (n === -1) {
    return `if (${s} === 200) console.log('${s}');`;
  } else {
    return f(n - 1, s + n) + f(n - 1, s + '+' + n) + f(n - 1, s + '-' + n);
  }
}

eval(f(8, '9'));
vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)
Ответ на: комментарий от anonymous

Чего сразу ужас?!

Это просто проверка генератора декартово произведения на баш

$ echo {0..9}{a..z}

вот переделанный вариант без лишних форков

digits="9876543210"
ops="+,-,' '"
result="200"

for (( i=0; i<${#digits}; i=i+1 ))
do
    expr_evl="$expr_evl"'${digits:'$i':1}${l:'$i':1}'
done

len=$((${#digits}-1))
s=$(printf "%0.s{$ops}" $(seq $len))

while read l
do
    l=${l//\"/}
    eval "e=$expr_evl"
    e=${e// /}
    eval r=$(( $e ))
    [[ $r == $result ]] && echo $e=$result
done < <(eval "printf '\"%s\"\n' $s")
9-8+7-6-5-4-3+210=200
9-8-7-6-5+4+3+210=200
98+76-5+43-2-10=200
98-7+65+43+2-1+0=200
98-7+65+43+2-1-0=200

real	0m0,831s
user	0m0,749s
sys	0m0,153s
anonymous
()
Ответ на: комментарий от anonymous

Чего сразу ужас?!

Ну чего вы сразу в штыки? Иногда «ужас» это даже комплимент. Вот как с тем интересным решением выше.

Вы лучше расскажите, что у вас там происходит, а-то в скрипты на баше иногда бывает непросто вникать, особенно, если обычно этого предпочитаешь избегать.

witaway
()

Без обфускацииминификации, но без eval.

(defun concat-digit (number digit)
  (if (plusp number)
      (+ (* number 10) digit)
      (- (* number 10) digit)))

(defun solve (first-digit target)
  (labels ((iter (last-number next-digit expr current-value)
             (if (= next-digit -1)
                 (when (= current-value target)
                   (format t "~A = ~A~%" expr target))
                 (let ((next-number (concat-digit last-number next-digit)))
                   ;; +
                   (iter next-digit
                         (1- next-digit)
                         (format nil "~A+~A" expr next-digit)
                         (+ current-value next-digit))
                   ;; -
                   (iter (- next-digit)
                         (1- next-digit)
                         (format nil "~A-~A" expr next-digit)
                         (- current-value next-digit))
                   ;; ничего
                   (iter next-number
                         (1- next-digit)
                         (format nil "~A~A" expr next-digit)
                         (+ current-value (- last-number) next-number))))))
    (iter first-digit (1- first-digit) (format nil "~A" first-digit) first-digit)))

(solve 9 200)
9-8+7-6-5-4-3+210 = 200
9-8-7-6-5+4+3+210 = 200
98+76-5+43-2-10 = 200
98-7+65+43+2-1+0 = 200
98-7+65+43+2-1-0 = 200

@Lrrr Стек не порвёт, тут всего O(N) нужно, при N не превышающем 9. В твоём варианте вроде бы тоже, но не берусь точно сказать что там будет с yield.

Gentooshnik ★★★★★
()
Последнее исправление: Gentooshnik (всего исправлений: 1)