Решение линейного Диофантового уравнения(см. Описание Для примеров)

позвольте мне начать с разъяснения того, что (прежде чем вы, ребята, уволите меня), это не проблема домашней работы, и я не студент университета. :)

редактировать Благодаря @Klas и другим, мой вопрос теперь сводится к математическому уравнению, которое необходимо решить программно.

Я ищу алгоритм/код, который решает Linear Diophantine Equation. Для таких простых смертных, как я, вот как выглядит такое уравнение:

Пример 1: 3x + 4y + 5z = 25 (найти все возможные значения x, y, z)

Пример 2: 10p + 5q + 6r + 11s = 224 (найти все возможные значения p, q,r, s)

Пример 3: 8p + 9q + 10r + 11s + 12t = 1012 (найти все возможные значения p, q,r,s, t)

Я попытался погуглить безрезультатно. Я бы подумал, что какой-то код уже будет написан, чтобы решить это. Дайте мне знать, если вы, ребята, столкнулись с какой-то библиотекой, которая уже реализовала это. И если решение в Java, ничто не может быть круче!. Алгоритм/псевдо-код также будет делать. Спасибо.

8 ответов


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

предположения: входные данные пользователя (множители) всегда являются различными целыми положительными числами. Коэффициенты должны быть неотрицательными целыми числами.

:
Of the multiplicands, let M be the largest.
Calculate C=floor(F/M).
If F=M*C, output solution of the form (0,0,...,C) and decrement C
If M is the only multiplicand, terminate processing
Loop from C down to 0 (call that value i)
  Let F' = F - i*M
  Recursively invoke this algorithm:
    The multiplicands will be the current set minus M
    The goal value will be F'
  For each solution output by the recursive call:
     append i to the coefficient list and output the solution

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

Я предлагаю Вам google по Диофантовым уравнениям.

Я нашел объяснение для вас.


я случайно написал Java-код для этого. Пожалуйста, угощайтесь. Решения широко не тестируются, но, похоже, до сих пор работают хорошо.

package expt.qp;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class LinearDiophantine {

    private Map<Integer, Integer> sol = new LinkedHashMap<Integer, Integer>();
    private Map<Integer, Integer> coeff = new HashMap<Integer, Integer>();

    /**
     * @param args
     */
    public static void main(String[] args) {
        // Fill up the data
        // 3x + 4y + 5z + 3a = 25
        LinearDiophantine ld = new LinearDiophantine();
        ld.coeff.put(1, 1);ld.coeff.put(2, 2);ld.coeff.put(3, 3);ld.coeff.put(4, 4);
        Map<Integer, Integer> coeffCopy = new HashMap<Integer, Integer>(ld.coeff);
        int total=30;

        // Real algo begins here
        ld.findPossibleSolutions(total, coeffCopy);

    }

    private void findPossibleSolutions(int total, Map<Integer, Integer> coeff) {
        int index=returnLargestIndex(coeff);
        int range = (int) Math.floor(total/coeff.get(index));
        if(range*coeff.get(index) == total) {
            sol.put(index, range);
            displaySolution();
            //System.out.println();
            range--;
        }
        if(coeff.size() == 1) {
            return;
        }
        while(range>=0) {
            int remTotal = total - range*coeff.get(index);
            Map<Integer, Integer> coeffCopy = new HashMap<Integer, Integer>(coeff);
            coeffCopy.remove(index);
            sol.put(index, range);
            findPossibleSolutions(remTotal, coeffCopy);
            range--;
        }
    }

    private void displaySolution() {
        int total = 0;
        for(int i : sol.keySet()) {
            //System.out.print(coeff.get(i)+"("+sol.get(i)+"), ");
            total = total + (coeff.get(i)*sol.get(i));
        }
        if(total != 30)
            System.out.print(total+",");
    }

    /**
     * @param coeff
     */
    private int returnLargestIndex(Map<Integer, Integer> coeff) {
        int largestKey = coeff.keySet().iterator().next();
        for(int i : coeff.keySet()) {
            if(coeff.get(i)>coeff.get(largestKey)) {
                largestKey=i;
            }
        }
        return largestKey;
    }

}

добавление к очень точному ответу Класа:

10-я задача Гильберта спросила, существует ли алгоритм для определения того, имеет ли решение произвольное диофантовое уравнение. Такой алгоритм существует для решения диофантовых уравнений первого порядка. Однако невозможность получения общего решения была доказана Юрием Матиясевичем в 1970 году

взято из: С Wolfram MathWorld


алгоритм грубой силы выглядит следующим образом (3 переменных случая):

int sum = 25;
int a1 = 3;
int a2 = 4;
int a3 = 5;
for (int i = 0; i * a1 <= sum; i++) {
    for (int j = 0; i * a1 + j * a2 <= sum; j++) {
        for (int k = 0; i * a1 + j * a2 + k * a3 <= sum; k++) {
            if (i * a1 + j * a2 + k * a3 == sum) {
                System.out.println(i + "," + j + "," + k);
            }
        }
    }
}

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

этот алгоритм O(f(size, a)^N) для некоторой функции f.

  • мы можем установить границы f следующим образом: size / MaxValue(a) <= f(size, a) <= size / MinValue(a).
  • в худшем случае (когда все a[i]С 1) f(size, a) is size.

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


если вы готовы раскошелиться на 34 евро для Springer Verlag, вот ссылка на статью который (согласно реферату) включает в себя алгоритм решения n переменных.


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

давайте начнем с самой простой ситуации, когда есть два unkowns a*x + b*y = c:

первым шагом является использование алгоритм Евклида чтобы найти GCD a и b, назовем егоd. В качестве бонуса алгоритм предоставляет x' и y' такие, что a*x' + b*y' = d. Если d не делит c, то решения нет. В противном случае решение:

x = x' * (c/d)
y = y' * (c/d)

второй шаг-найти все решения. Это означает, что мы должны найти все p и q такое, что a*p + b*q = 0. Если оба (x,y) и (X, Y) решения, то

a * (X-x) + b * (Y-y) = 0

ответ p = b/d и q = -a/d здесь d = GCD(a,b) и уже рассчитывается на шаге 1. Общее решение теперь:

x = x' * (c/d) + n * (b/d)
y = y' * (c/d) - n * (a/d)

где n является целым числом.

первый шаг легко расширить до нескольких переменных. Я не уверен в обобщении второго шага. Мое первое предположение было бы найти решение для всех пар коэффициентов и объединить эти решения.


Это решение в Perl. скорее взломать с помощью Regex.

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

мы можем использовать следующий скрипт для 3x + 2y + 5z = 40

#!/usr/bin/perl
$_ = 'o' x 40;
$a = 'o' x 3;
$b = 'o' x 2;
$c = 'o' x 5;
$_ =~ /^((?:$a)+)((?:$b)+)((?:$c)+)$/;
print "x = ", length()/length($a), "\n";
print "y = ", length()/length($b), "\n";
print "z = ", length()/length($c), "\n";

выход: x=11, y = 1, z = 1

известный старший играет на фортепиано головоломка заканчивается как 3 переменных уравнения

этот метод применяется для условие что переменные на самом деле положительно, и константа положительна.


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

точнее, если у вас есть n переменные, сумма которых составляет X, тогда у вас будет O(Xn-1) ответы. X и n Не обязательно быть очень большим, чтобы это стало проблемой.

тем не менее, вот некоторые Python, который довольно эффективно вычисляет все необходимая информация для кодирования ответа:

def solve_linear_diophantine (*coeff_tuple):
    coeff = list(coeff_tuple)
    constant = coeff.pop()

    cached = []
    for i in range(len(coeff)):
        # Add another cache.
        cached.append({})

    def solve_final (i, remaining_constant):
        if remaining_constant in cached[i]:
            return cached[i][remaining_constant]
        answer = []
        if i+1 == len(coeff):
            if 0 == remaining_constant%coeff[i]:
                answer = [(remaining_constant/coeff[i], [])]
        else:
            for j in range(remaining_constant/coeff[i] + 1):
                finish = solve_final(i+1, remaining_constant - j*coeff[i])
                if finish is not None:
                    answer.append((j, finish))
        if 0 == len(answer):
            cached[i][remaining_constant] = None
            return None
        else:
            cached[i][remaining_constant] = answer
            return answer

    return solve_final(0, constant)

когда я говорю "кодировать", структура данных выглядит так. Для каждого возможного коэффициента, мы получим массив (coefficient, [subanswers]). Когда это возможно, он повторно использует subanswers, чтобы сделать структуру данных как можно меньше. Если вы не можете рекурсивно развернуть это обратно в массив ответов, и при этом вы будете довольно эффективны. (На самом деле это O(nX).) Вы будете делать очень мало повторения логики, чтобы обнаружить то же самое факты снова и снова. (Однако возвращаемый список может получить очень большой просто потому, что есть большой список ответов, которые должны быть возвращены.)