合計がNになるすべての4乗の組み合わせをどれくらい早く見つけることができますか?


12

Stack Overflowで質問がありました(こちら):

整数与えられると、方程式A 2 + B 2 + C 2 + D 2 = Nを解くA B CおよびDNの整数値のすべての可能な組み合わせを出力します。A,B,CDA2+B2+C2+D2=N

この質問は、もちろん、バチェットの数論における推測(彼の証明からラグランジュの四乗定理と呼ばれることもある)に関連しています。単一の解決策を見つける方法を議論するいくつかの論文がありますが、特定のNのすべての解決策を見つけることができる速さ(つまり、すべての順列ではなく、すべての組み合わせ)を見つけることについて話すものを見つけることができませんでした。N

私はそれについてかなり考えてきましたが、時間と空間で解決できるように思われます。ここで、Nは望ましい合計です。しかし、主題に関する事前情報が不足しているため、それが私の側の重要な主張なのか、ささいな、明白な、またはすでに知られている結果なのかわかりません。O(N)N

それで、問題は、与えられたすべての4乗和をどれだけ速く見つけることができるかということです。N


OK、私が考えていた(ほぼ)O(N)アルゴリズムです。最初の2つのサポート関数、最も近い整数平方根関数:

    // the nearest integer whose square is less than or equal to N
    public int SquRt(int N)
    {
        return (int)Math.Sqrt((double)N);
    }

そして、0からNまでのすべてのTwoSquareペアを返す関数:

    // Returns a list of all sums of two squares less than or equal to N, in order.
    public List<List<int[]>> TwoSquareSumsLessThan(int N)
    {
        //Make the index array
        List<int[]>[] Sum2Sqs = new List<int[]>[N + 1];

        //get the base square root, which is the maximum possible root value
        int baseRt = SquRt(N);

        for (int i = baseRt; i >= 0; i--)
        {
            for (int j = 0; j <= i; j++)
            {
                int sum = (i * i) + (j * j);
                if (sum > N)
                {
                    break;
                }
                else
                {
                    //make the new pair
                    int[] sumPair = { i, j };
                    //get the sumList entry
                    List<int[]> sumLst;
                    if (Sum2Sqs[sum] == null)
                    {   
                        // make it if we need to
                        sumLst = new List<int[]>();
                        Sum2Sqs[sum] = sumLst;
                    }
                    else
                    {
                        sumLst = Sum2Sqs[sum];
                    }
                    // add the pair to the correct list
                    sumLst.Add(sumPair);
                }
            }
        }

        //collapse the index array down to a sequential list
        List<List<int[]>> result = new List<List<int[]>>();
        for (int nn = 0; nn <= N; nn++)
        {
            if (Sum2Sqs[nn] != null) result.Add(Sum2Sqs[nn]);
        }

        return result;
    }

最後に、アルゴリズム自体:

    // Return a list of all integer quads (a,b,c,d), where:
    //      a^2 + b^2 + c^2 + d^2 = N,
    // and  a >= b >= c >= d,
    // and  a,b,c,d >= 0
    public List<int[]> FindAllFourSquares(int N)
    {
        // get all two-square sums <= N, in descending order
        List<List<int[]>> Sqr2s = TwoSquareSumsLessThan(N);

        // Cross the descending list of two-square sums <= N with
        // the same list in ascending order, using a Merge-Match
        // algorithm to find all combinations of pairs of two-square
        // sums that add up to N
        List<int[]> hiList, loList;
        int[] hp, lp;
        int hiSum, loSum;
        List<int[]> results = new List<int[]>();
        int prevHi = -1;
        int prevLo = -1;

        //  Set the Merge sources to the highest and lowest entries in the list
        int hi = Sqr2s.Count - 1;
        int lo = 0;

        //  Merge until done ..
        while (hi >= lo)
        {
            // check to see if the points have moved
            if (hi != prevHi)
            {
                hiList = Sqr2s[hi];
                hp = hiList[0];     // these lists cannot be empty
                hiSum = hp[0] * hp[0] + hp[1] * hp[1];
                prevHi = hi;
            }
            if (lo != prevLo)
            {
                loList = Sqr2s[lo];
                lp = loList[0];     // these lists cannot be empty
                loSum = lp[0] * lp[0] + lp[1] * lp[1];
                prevLo = lo;
            }

            // do the two entries' sums together add up to N?
            if (hiSum + loSum == N)
            {
                // they add up, so cross the two sum-lists over each other
                foreach (int[] hiPair in hiList)
                {
                    foreach (int[] loPair in loList)
                    {
                        // make a new 4-tuple and fill it
                        int[] quad = new int[4];
                        quad[0] = hiPair[0];
                        quad[1] = hiPair[1];
                        quad[2] = loPair[0];
                        quad[3] = loPair[1];

                        // only keep those cases where the tuple is already sorted
                        //(otherwise it's a duplicate entry)
                        if (quad[1] >= quad[2]) //(only need to check this one case, the others are implicit)
                        {
                            results.Add(quad);
                        }
                        //(there's a special case where all values of the 4-tuple are equal
                        // that should be handled to prevent duplicate entries, but I'm
                        // skipping it for now)
                    }
                }
                // both the HI and LO points must be moved after a Match
                hi--;
                lo++;
            }
            else if (hiSum + loSum < N)
            {
                lo++;   // too low, so must increase the LO point
            }
            else    // must be > N
            {
                hi--;   // too high, so must decrease the HI point
            }
        }
        return results;
    }

前述したように、O(N)にかなり近いはずです。ただし、Yuval Filmusが指摘しているように、Nの4乗解の数はオーダー(N ln ln N)になる可能性があるため、このアルゴリズムはそれ以下。


はい、投稿してください。私はまだ線形アルゴリズムの詳細を開発していますが、それが有効であると確信しています。
–RBarryYoung

5
記録に関しては、解が存在する場合があるため、Oを実際に取得することはできません。Ω(NloglogN)アルゴリズムを。O(N)
ユヴァルフィルマス

1
ここからは、メインのwhileループ内の2つのforeach()ループからcatch(および追加の非線形因子)が来るように見えます。合計時間は基本的に、そして問題は、hiListとloListのサイズが必ずしも定数によって制限されないことです。i=0N/2|hiListNi||loListi|
スティーブン・スタドニッキ

はい、それは正しいですが、最初のiの範囲は0からapprxであるため、数式は少しずれています。N PI / 8、2番目にiの値の一部のみがhiList(Ni)+ loList(i)= Nを満たしているため、すべてが追加されるわけではありません。いずれにしても、これを修正する方法はありません。これにより、O(N log(log(N)))の最小の複雑さが得られることを確認してください
RBarryYoung

ただし、O(最大(N、「解の数」))で実行するアルゴリズムを使用して、O(n)のスペースを取ることができます。
gnasher729

回答:


15

JuhoのアルゴリズムはO N )に改善できますO(N) meet-in-the-middleを使用アルゴリズムに。すべてのペアを乗り越える ; 各ペアについて、このようなM=A2+B2N、店舗ABいくつかの配列におけるTの長さN(各位置Mは、リンクされたリストに格納されるかもしれないいくつかのペアを含むことができます)。Tの対応するセルが空でないようにペアMNMを調べます。A,BNM=A2+B2N(A,B)TNMM,NMT

Ω(NloglogN)N8σ(N)σ(N)(eγϵ)NloglogN

N


うーん、meet-in-the-middleのことは、私が取り組んでいる(ほとんど完了している)ものと非常によく似ています。それは同じように聞こえますか?
–RBarryYoung

1
おそらく同じことです。meet-in-the-middleは非常に一般的なヒューリスティックであるため、多くの異なる名前が必要です。
ユヴァルフィルマス

σ(N)

σ(N)ο(N)

1
除数の合計は確かに機能します。
ユヴァルフィルマス

5

o(N2)A,B,C,DNO(N2)

O(log2n)O(log2nloglogn)


[1] MO Rabin、JO Shallit、数論におけるランダム化アルゴリズム、ピュアおよび応用数学に関するコミュニケーション39(1986)、no。S1、pp。S239–S256


単純なアルゴリズムの場合、A、B、Cのループのみが必要で、Dを計算して整数であることを確認します。A≤B≤C≤Dが必要な場合は、かなり小さい定数でO(N ^ 1.5)を取得する必要があります。
gnasher729

約0.04 N ^ 1.5トリプル(A、B、C)、およびN-A ^ 2-B ^ 2-C ^ 2が正方形であることの確認は、非常に迅速に実行できます。
gnasher729

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.