public static (int number, int newNumber) Solve(int[] numbers) { Array.Sort(numbers); int maxSum = 0; for (int i = 0; i < numbers.Length; i++) { maxSum += numbers[i]; } PartialSumsData data = new PartialSumsData(maxSum); BitArraySlim currSums = new BitArraySlim(1); currSums.ForceSet(0, 1); CreateAllSumsDatas(numbers, currSums, data); return(CreateCollisionAvoidanceArray(data.Sums, data.Datas, data)); }
private static (int number, int newNumber) CreateCollisionAvoidanceArray(BitArraySlim sums, BestSumsData bestData, PartialSumsData data) { SumsData sumData = bestData.Data.ToSumsData(bestData.Number, data.SumsCount); foreach (var unique in sumData.Uniques) { sums.ForceSet(unique, 0); } for (int i = 1; i <= sums.Length;) { bool foundObstacle = false; foreach (var newSum in sumData.NewSums) { int overlapIndex = newSum - (bestData.Number - i); int offset = 0; while (overlapIndex + offset < sums.Length && sums[overlapIndex + offset] == 1) { offset++; } i += offset; if (offset > 0) { foundObstacle = true; break; } } if (!foundObstacle) { return(bestData.Number, i); } } throw new Exception("impossible!.... i thought"); }
private static void CreateAllSums(int number, BitArraySlim currSums, PartialSumsData data) { data.Sums = CreatePartialSums(new int[] { number }, currSums, data); data.SumsCount = BoolArrayTrueCount(data.Sums); }
private static PreSumsData FinishCreateSumsData(int number, BitArraySlim currSums, int currSumsCount, PartialSumsData data) { if (data.SumsCount != -1) { int uniqueSums = data.SumsCount - currSumsCount; return(new PreSumsData(currSums, uniqueSums)); } if (data.SumsCount == -1) { CreateAllSums(number, currSums, data); data.SumsCount = BoolArrayTrueCount(data.Sums); } int uniques = 0; for (int i = 0; i < currSums.Length; i++) { if (currSums[i] == 1) { int newSum = i + number; if (newSum >= currSums.Length) { uniques++; } else if (currSums[newSum] == 0) { uniques++; } } } return(new PreSumsData(currSums, uniques)); }
private static BitArraySlim CreatePartialSums(Span <int> numbers, BitArraySlim currSums, PartialSumsData data) { int maxSum = currSums.Length; for (int i = 0; i < numbers.Length; i++) { maxSum += numbers[i]; } BitArraySlim newSums = data.Storage.Pop(maxSum); currSums.CopyToAndClearRest(newSums); int prevMaxSum = currSums.Length - 1; for (int i = 0; i < numbers.Length; i++) { CreateSumsVectorized(prevMaxSum, numbers[i], newSums); prevMaxSum += numbers[i]; } return(newSums); }
private static bool CreateAllSumsDatas(Span <int> numbers, BitArraySlim currSums, PartialSumsData data) { if (numbers.Length > 1) { int midPoint = numbers.Length / 2; Span <int> firstPart = numbers.Slice(0, midPoint); Span <int> secondPart = numbers.Slice(midPoint); BitArraySlim secondPartSums = CreatePartialSums(secondPart, currSums, data); if (!CreateAllSumsDatas(firstPart, secondPartSums, data)) { data.Storage.Push(secondPartSums); } BitArraySlim firstPartSums = CreatePartialSums(firstPart, currSums, data); if (!CreateAllSumsDatas(secondPart, firstPartSums, data)) { data.Storage.Push(firstPartSums); } } else { data.Created++; int actualSumCount = BoolArrayTrueCount(currSums); if (data.SumsCount - actualSumCount > data.Minuniques) { return(false); } int number = numbers[0]; if (!data.FoundData.Contains(number)) { BestSumsData newData = new BestSumsData(number, FinishCreateSumsData(number, currSums, actualSumCount, data)); data.Minuniques = Math.Min(data.Minuniques, data.Datas.Data.Uniques); if (newData.Data.Uniques < data.Datas.Data.Uniques || (newData.Data.Uniques == data.Datas.Data.Uniques && newData.Number < data.Datas.Number)) { if (data.Datas.Data.BitArray != null) { data.Storage.Push(data.Datas.Data.BitArray); } data.Datas = newData; return(true); } } } return(false); }