Une question a été posée à Stack Overflow ( ici ):
Compte tenu d' un nombre entier , imprimer toutes les combinaisons possibles des valeurs entières de et qui résolvent l'équation .A , B , C D A 2 + B 2 + C 2 + D 2 = N
Cette question est bien sûr liée à la conjecture de Bachet en théorie des nombres (parfois appelée théorème des quatre carrés de Lagrange en raison de sa preuve). Il y a des articles qui expliquent comment trouver une solution unique, mais je n'ai pas pu trouver quoi que ce soit qui parle de la vitesse à laquelle nous pouvons trouver toutes les solutions pour un particulier (c'est-à-dire toutes les combinaisons , pas toutes les permutations ).
J'y ai beaucoup réfléchi et il me semble que cela peut être résolu dans le temps et l'espace , où est la somme souhaitée. Cependant, faute d'informations préalables sur le sujet, je ne sais pas s'il s'agit d'une revendication significative de ma part ou simplement d'un résultat trivial, évident ou déjà connu.
Donc, la question est alors, à quelle vitesse pouvons-nous trouver toutes les sommes des quatre carrés pour un N donné ?
OK, voici l'algorithme (presque) O (N) auquel je pensais. Deux premières fonctions de support, une fonction de racine carrée entière la plus proche:
// the nearest integer whose square is less than or equal to N
public int SquRt(int N)
{
return (int)Math.Sqrt((double)N);
}
Et une fonction pour renvoyer toutes les paires TwoSquare sommant de 0 à N:
// 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;
}
Enfin, l'algorithme lui-même:
// 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;
}
Comme je l'ai déjà dit, il devrait être assez proche de O (N), cependant, comme le souligne Yuval Filmus, car le nombre de solutions à quatre carrés de N peut être d'ordre (N ln ln N), alors cet algorithme ne pourrait pas être moins que ça.