มีคำถามที่ Stack Overflow ( ที่นี่ ):
ได้รับจำนวนเต็ม , พิมพ์ออกมารวมกันเป็นไปได้ทั้งหมดของค่าจำนวนเต็มของและซึ่งการแก้สมการNA , B , C D A 2 + B 2 + C 2 + D 2 = N
คำถามนี้แน่นอนว่าเกี่ยวข้องกับทฤษฎีการคาดเดาของ Bachetในทฤษฎีจำนวน (บางครั้งเรียกว่าทฤษฎีบท Four Square ของ Lagrange เพราะหลักฐานของเขา) มีเอกสารบางฉบับที่พูดถึงวิธีการหาทางออกเดียว แต่ฉันไม่สามารถหาอะไรที่พูดถึงความเร็วที่เราสามารถหาวิธีแก้ปัญหาทั้งหมดสำหรับเฉพาะเจาะจง(นั่นคือการรวมกันทั้งหมดไม่ใช่การเปลี่ยนลำดับทั้งหมด)
ฉันคิดอยู่นิดหน่อยและดูเหมือนว่าฉันสามารถแก้ไขได้ในเวลาและสถานที่โดยที่คือผลรวมที่ต้องการ อย่างไรก็ตามหากขาดข้อมูลก่อนหน้านี้ในเรื่องนี้ฉันไม่แน่ใจว่านี่เป็นข้อเรียกร้องที่มีนัยสำคัญในส่วนของฉันหรือเพียงแค่ผลลัพธ์เล็กน้อยที่เห็นได้ชัดหรือเป็นที่รู้จักแล้วN
ดังนั้นคำถามก็คือเราจะหาผลบวกสี่สแควร์ทั้งหมดสำหรับกำหนดได้เร็วแค่ไหน?
ตกลงนี่เป็นอัลกอริทึม O (N) ที่ฉันคิด สองฟังก์ชั่นแรกที่รองรับฟังก์ชั่นสแควร์รูทจำนวนเต็มที่ใกล้ที่สุด:
// the nearest integer whose square is less than or equal to N
public int SquRt(int N)
{
return (int)Math.Sqrt((double)N);
}
และฟังก์ชั่นเพื่อส่งคืนคู่ TwoSquare ทั้งหมดที่รวมจาก 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;
}
ในที่สุดอัลกอริทึมของตัวเอง:
// 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 สามารถเป็นระเบียบได้ (N ln ln N) ดังนั้นอัลกอริทึมนี้ไม่สามารถ น้อยกว่านั้น