10

(皆さんが私を解雇する前に)これは宿題の問題ではなく、私は大学生ではないことを明確にすることから始めましょう. :)

編集 @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 にある場合、これほど優れたものはありません!. アルゴリズム/疑似コードも同様です。どうもありがとう。

4

8 に答える 8

3

ブルートフォース再帰は、値または値の数をどれだけ大きくできるかに応じて、オプションです。

前提: ユーザー入力 (被乗数) は常に異なる正の整数です。検出される係数は、負でない整数でなければなりません。

アルゴリズム:

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
于 2011-04-01T12:39:20.647 に答える
2

私はたまたまこのための 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;
    }

}
于 2011-07-15T08:35:52.260 に答える
2

これはプログラミングの問題ではなく、数学の問題です。適切なアルゴリズムがあれば、それを実装するのはそれほど難しくありません。

ディオファントス方程式でググることをお勧めします。

私はあなたのための説明を見つけました。

于 2011-04-01T12:29:29.580 に答える
1

解決策がないか、無限に多いかのどちらかです。多くの場合、ソリューションが一致しなければならない追加の制約があります。これはあなたの問題に当てはまりますか?

2つの未知数がある最も単純な状況から始めましょうa*x + b*y = c

最初のステップは、ユークリッドアルゴリズムを使用してとのGCDを見つけることです。これを、ab呼びましょうd。ボーナスとして、アルゴリズムは次のようなものを提供x'します。が分割されない場合、解決策はありません。それ以外の場合の解決策は次のとおりです。y'a*x' + b*y' = ddc

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

2番目のステップは、すべての解決策を見つけることです。これは、すべてpを見つけなければならないことを意味qa*p + b*q = 0ます。(x,y)とが両方とも(X, Y)解決策である場合、

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

これに対する答えはp = b/d、ステップ1ですでに計算されているq = -a/d場所です。現在の一般的な解決策は次のとおりです。d = GCD(a,b)

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

ここで、nは整数です。

最初のステップは、複数の変数に簡単に拡張できます。2番目のステップを一般化することについてはよくわかりません。私の最初の推測は、係数のすべてのペアの解を見つけて、これらの解を組み合わせることです。

于 2011-04-03T07:34:06.247 に答える
1

これは Perl でのソリューションです。正規表現を使用したハックです。

このブログ投稿に従って、正規表現を使用して代数方程式を解きます。

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($1)/length($a), "\n";
print "y = ", length($2)/length($b), "\n";
print "z = ", length($3)/length($c), "\n";

出力: x=11、y = 1、z = 1

有名な最年長者がピアノを弾くパズルは、最終的に 3 変数の方程式になります。

この方法は、変数が実際に正であり、定数が正であるという条件に適用されます。

于 2013-08-09T01:59:41.413 に答える
1

クラスの非常に正確な答えに追加します:

ヒルベルトの 10 番目の問題は、任意のディオファントス方程式に解があるかどうかを判断するためのアルゴリズムが存在するかどうかを尋ねました。このようなアルゴリズムは、1 次ディオファントス方程式の解に対して存在します。しかし、一般解を得ることが不可能であることは、1970 年に Yuri Matiyasevich によって証明されました。

出典:Wolfram MathWorld

于 2011-04-01T12:39:39.993 に答える
1

ブルート フォース アルゴリズムは次のとおりです (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])1f(size, a)ですsize

いずれにせよ、これは の大きな値に対してはかなり恐ろしいことですN。したがって、再帰的な N 変数アルゴリズムはより洗練されていますが、おそらくあまり実用的ではありません。


34 ユーロを Springer Verlag に支払う意思がある場合は、(要約によると) N 変数のケースを解決するためのアルゴリズムを含む論文へのリンクを次に示します。

于 2011-04-01T12:40:57.027 に答える
0

これを行うライブラリがない理由は、順列を行うライブラリが見つからない理由と似ています。大量のデータを生成するため、これはおそらく間違ったことです。

より正確には、n変数の合計が である場合、答え Xが得られます。これが問題になるために非常に大きくする必要はありません。O(Xn-1)Xn

そうは言っても、答えをエンコードするために必要なすべての情報をかなり効率的に把握する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])。可能な限りサブアンサーを再利用して、データ構造を可能な限り小さくします。できない場合は、これを再帰的に展開して回答の配列に戻すことができます。そうすることで、かなり効率的になります。(実際にはそうですO(nX)。) 同じ事実を何度も何度も発見するために、論理をほとんど繰り返さないでしょう。(ただし、返される回答のリストが大量にあるという理由だけで、返されるリストが非常に大きくなる場合があります。)

于 2011-04-03T06:33:11.193 に答える