Не могу решить алгоритм php с вариациями

Я должен найти все возможные решения из заданной последовательности целых чисел, равной заданному числу.

например: 1,2,3,4,5,6,7,8,9, что равно 100 ответ: 1 + 23-4 + 56 + 7 + 8 + 9 = 100

Мое решение для другой суммы в примере 25:

$arr = array(1, 2, 3, 4, 5, 6, 7, 8, 9);
$n = count($arr);
$sum = 25;

function checkSol() {
    global $arr;
    global $n;
    global $sum;
    $tempSum = 0;
    for ($i = 0; $i < $n; $i++) {
        $tempSum += $arr[$i];
    }

    if ($tempSum == $sum) {
        for ($i = 0; $i < $n; $i++) {
            if ($arr[$i] > 0) {
                printf("+%d ", $arr[$i]);
            } else {
                printf("%d ", $arr[$i]);
            }
        }
        printf(" = %d\n", $tempSum);
        echo "<br/>";
    }
}

function variate($i = 0) {
    global $arr;
    global $n;
    if ($i >= $n) {
        checkSol();
        return;
    }

    $arr[$i] = abs($arr[$i]);
    variate($i + 1);
    $arr[$i] = -abs($arr[$i]);
    variate($i + 1);
}

variate();

Вот результат:

+1 +2 +3 -4 +5 -6 +7 +8 +9 = 25 
+1 +2 -3 +4 +5 +6 -7 +8 +9 = 25 
+1 -2 +3 +4 +5 +6 +7 -8 +9 = 25 
+1 -2 -3 +4 -5 +6 +7 +8 +9 = 25 
-1 +2 +3 +4 +5 +6 +7 +8 -9 = 25 
-1 +2 +3 -4 -5 +6 +7 +8 +9 = 25 
-1 +2 -3 +4 +5 -6 +7 +8 +9 = 25 
-1 -2 +3 +4 +5 +6 -7 +8 +9 = 25 
-1 -2 -3 -4 +5 +6 +7 +8 +9 = 25 

Настоящая проблема здесь в том, что я не могу объединить все возможные варианты, как в примере в начале. Заранее спасибо.

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

Rafael 29.08.2018 11:25

Вы можете использовать мое решение в качестве ответа в stackoverflow.com/questions/50240628/…, чтобы получить перестановку, а затем проверить сумму, равную 100/25

dWinder 29.08.2018 11:40

@Rafael Количество перестановок совсем невелико. Последовательность 123456789 имеет только восемь интервалов (1-2, 2-3, 3-4, 4-5, 5-6, 6-7, 7-8 и 8-9). В каждом интервале у вас есть три варианта (+, - или пустая строка), поэтому общее количество перестановок составляет 3 ^ 8, что составляет 6561. Их можно легко проверить за доли секунды.

r3mainer 29.08.2018 14:48

В этом случае вы считаете, что перестановки происходят в последовательности, @Squeamish, но, учитывая уровень задачи, я бы не предположил, что это так просто. Учитывая, что ему нужны были все комбинации плюс / минус из чисел, которые могли быть такими: 91, 38, 42, 75, 6. Если вы рассматриваете числа, объединяющиеся внутри массива, я бы рассмотрел также любую комбинацию из этих чисел.

Rafael 29.08.2018 14:59

И это, конечно, даже без учета того, что интервалы могут состоять более чем из двух цифр. 123−45−6+7+9+8 = 96, например, не равен 100, но его следует принять во внимание, прежде чем все суммировать. Пока не заявлено, что перестановки должны иметь максимум две цифры, я бы сказал, что это чрезмерное упрощение, чтобы предполагать это.

Rafael 29.08.2018 15:33
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
7
5
242
1

Ответы 1

Обновлено: Кредит @ m69 за огромное упрощение.

Ваша проблема может быть решена с помощью концепций, взятых из Звезды и полосы.

Сначала нам нужно взглянуть на ваш пример, чтобы понять, как применяются эти концепции. У нас есть последовательность 1, 2, 3, 4, 5, 6, 7, 8, 9 и решение а1 + 23 - 4 + 56 + 7 + 8 + 9. Отметим, что порядок имеет значение, если мы рассматриваем математическое определение последовательности, поэтому нам не нужно рассматривать перестановки самих чисел. Давайте посмотрим на вашу последовательность через призму звезд и полос:

1    2    3    4    5    6    7    8    9
   |   |    |    |     |    |    |    |    <<-- This is where either +, -, or a space will go

Нам нужно подогнать все перестановки вектора (“+”, “-“, “”), где встречаются полосы. Это означает, что мы должны сгенерировать все перестановки с повторением длины 8. После того, как мы вставим эти символы между (т. Е. Столбцы выше) числами в нашей последовательности, мы, наконец, сможем оценить строку.

Вот быстрая демонстрация алгоритма генерации перестановок с повторением в C++. Это просто и должно быть легко преобразовано (здесь - рабочий пример):

void permsWithRep(std::vector<int> v, int r) {

    int n = v.size();
    int r1 = r - 1, n1 = n - 1;
    std::vector<int> z(r, 0);
    int numRows = (int) std::pow(n, r);

    for (int i = 0; i < numRows; ++i) {
        for (int j = 0; j < r; ++j)
            std::cout << v[z[j]] << ' ';
        std::cout << std::endl;

        for (int k = r1; k >= 0; --k) {
            if (z[k] != n1) {
                ++z[k];
                break;
            } else {
                z[k] = 0;
            }
        }
    }
}

Чтобы эффективно вставить наши символы, нам нужно дополнить нашу исходную последовательность пустыми слотами между каждым числом, например:

1,  , 2,  , 3,  , 4,  , 5,  , 6,  , 7,  , 8,  , 9

Теперь мы можем вставить нашу перестановку символов в пустые слоты. Например. :

1,"+", 2,"-", 3,"", 4,"", 5,"", 6,"", 7,"", 8,"", 9

Затем мы сворачиваем вектор и оцениваем:

1 + 2 - 3456789  <<-- collapse
-3456786    <<-- evaluate

Вот полный код с использованием R и пакета RcppAlgos (я являюсь автором), который написан на C++:

getSolutions <- function(v, target, myOps = c("+", "-", "")) {
    n <- length(v)
    permExp <- RcppAlgos::permuteGeneral(myOps, n - 1, 
                                         repetition = TRUE)
    vEval <- vector(length = 2*n - 1)

    ## augmenting original sequence to create slot for symbols
    vEval[seq(1, 2*n - 1, 2)] <- v

    lapply(1:nrow(permExp), function(y) {

        ## insert symbols in empty slots
        vEval[seq(2, 2*n - 2, 2)] <- permExp[y, ]

        ## collapse and evaluate
        test <- eval(parse(text = paste0(vEval, collapse = "")))
        if (test == target)
            print(paste0(vEval, collapse = ""))
        test
    })
}

А вот демонстрация:

test100 <- getSolutions(1:9, 100)
[1] "1+2+3-4+5+6+78+9"
[1] "1+2+34-5+67-8+9"
[1] "1+23-4+5+6+78-9"
[1] "1+23-4+56+7+8+9"     <<-- example given by OP
[1] "12+3+4+5-6-7+89"
[1] "12+3-4+5+67+8+9"
[1] "12-3-4+5-6+7+89"
[1] "123+4-5+67-89"
[1] "123+45-67+8-9"
[1] "123-4-5-6-7+8-9"
[1] "123-45-67+89"

Наконец, поскольку нет ограничений на то, какие операции можно использовать, мы нужно подумать о других возможных способах достижения нашей целевой ценности. Приведенное выше решение легко распространяется на более общие случаи. Допустим, мы хотим добавить к смеси умножение. Без проблем:

testFourSymbols <- getSolutions(1:9, 100, c("*", "-", "+", ""))
[1] "1*2*3*4+5+6+7*8+9"
[1] "1*2*3*4+5+6-7+8*9"
[1] "1*2*3*4-5-6+78+9"
[1] "1*2*3+4+5+6+7+8*9"
[1] "1*2*3-4*5+6*7+8*9"
[1] "1*2*3-4+5+6+78+9"
[1] "1*2*3-45+67+8*9"
[1] "1*2*34+56-7-8-9"
[1] "1*2+3*4+5-6+78+9"
[1] "1*2+3+4*5+6+78-9"
[1] "1*2+3+45+67-8-9"
[1] "1*2+3-4+5*6+78-9"
[1] "1*2+34+5+6*7+8+9"
[1] "1*2+34+5-6+7*8+9"
[1] "1*2+34+5-6-7+8*9"
[1] "1*2+34+56+7-8+9"
[1] "1*2-3+4*5-6+78+9"
[1] "1*2-3+4-5+6+7+89"
[1] "1*23+4+5+67-8+9"
[1] "1*23-4+5-6-7+89"
[1] "1*234+5-67-8*9"
[1] "1+2*3+4*5-6+7+8*9"
[1] "1+2*3+4+5+67+8+9"
[1] "1+2*3-4-5+6+7+89"
[1] "1+2*34-56+78+9"
[1] "1+2+3*4-5-6+7+89"
[1] "1+2+3+4+5+6+7+8*9"
[1] "1+2+3-4*5+6*7+8*9"
[1] "1+2+3-4+5+6+78+9"
[1] "1+2+3-45+67+8*9"
[1] "1+2+34*5+6-7-8*9"
[1] "1+2+34-5+67-8+9"
[1] "1+2-3*4+5*6+7+8*9"
[1] "1+2-3*4-5+6*7+8*9"
[1] "1+23*4+5-6+7-8+9"
[1] "1+23*4-5+6+7+8-9"
[1] "1+23-4+5+6+78-9"
[1] "1+23-4+56+7+8+9"
[1] "1+23-4-5+6+7+8*9"
[1] "1+234-56-7-8*9"
[1] "1-2*3+4*5+6+7+8*9"
[1] "1-2*3-4+5*6+7+8*9"
[1] "1-2*3-4-5+6*7+8*9"
[1] "1-2+3*4*5+6*7+8-9"
[1] "1-2+3*4*5-6+7*8-9"
[1] "1-2+3*4+5+67+8+9"
[1] "1-2+3+45+6+7*8-9"
[1] "1-2-3+4*5+67+8+9"
[1] "1-2-3+45+6*7+8+9"
[1] "1-2-3+45-6+7*8+9"
[1] "1-2-3+45-6-7+8*9"
[1] "1-2-34+56+7+8*9"
[1] "1-23+4*5+6+7+89"
[1] "1-23-4+5*6+7+89"
[1] "1-23-4-5+6*7+89"
[1] "12*3-4*5+67+8+9"
[1] "12*3-4+5-6+78-9"
[1] "12*3-4-5-6+7+8*9"
[1] "12+3*4+5+6+7*8+9"
[1] "12+3*4+5+6-7+8*9"
[1] "12+3*4-5-6+78+9"
[1] "12+3*45+6*7-89"
[1] "12+3+4+5-6-7+89"
[1] "12+3-4+5+67+8+9"
[1] "12+34+5*6+7+8+9"
[1] "12+34-5+6*7+8+9"
[1] "12+34-5-6+7*8+9"
[1] "12+34-5-6-7+8*9"
[1] "12-3+4*5+6+7*8+9"
[1] "12-3+4*5+6-7+8*9"
[1] "12-3-4+5*6+7*8+9"
[1] "12-3-4+5*6-7+8*9"
[1] "12-3-4+5-6+7+89"
[1] "123+4*5-6*7+8-9"
[1] "123+4-5+67-89"
[1] "123+45-67+8-9"
[1] "123-4-5-6-7+8-9"
[1] "123-45-67+89"

Я знаю, что кода не было в php, но, надеюсь, идеи, представленные здесь, помогут вам понять, как решить вашу проблему.

@ m69, мне сейчас немного неловко. Ваш метод сводится к перестановке 3 элементов с повторениями длины 8. Способ проще.

Joseph Wood 29.08.2018 18:40

@ m69, готово. Спасибо за то, что убедились, что сообществу не пришлось страдать из-за предыдущей бессмыслицы.

Joseph Wood 29.08.2018 19:17

Я буду знать! Но кого это волнует!? XD

Rafael 29.08.2018 19:56

Другие вопросы по теме