Refactor Day10 to optimize pattern cost calculation by introducing bitmasking and grouping logic (speedup from 7 sec to 0.2 sec)
This commit is contained in:
parent
aaf32260d0
commit
1873ce8e66
|
|
@ -155,7 +155,7 @@ public class Day10 : IPuzzleSolver<long>
|
|||
yield break;
|
||||
}
|
||||
|
||||
foreach (var (pattern, cost) in GetPatternCosts(lampState.Length, buttons))
|
||||
foreach (var (_,(pattern, cost)) in GetPatternCosts(lampState.Length, buttons))
|
||||
{
|
||||
if (pattern.Zip(lampState, (pat, lam) => (pat % 2 == 1) == lam).All(x => x))
|
||||
{
|
||||
|
|
@ -166,30 +166,26 @@ public class Day10 : IPuzzleSolver<long>
|
|||
|
||||
private long GetMinCountButtonPressesForJoltageLevels(int[] joltages, int[][] buttons)
|
||||
{
|
||||
var patternCosts = GetPatternCosts(joltages.Length, buttons).ToArray();
|
||||
var patternCosts = GetPatternCosts(joltages.Length, buttons)
|
||||
.GroupBy(x => x.Item1)
|
||||
.ToDictionary(x => x.Key, x => x.Select(y => y.Item2).ToArray());
|
||||
var res = GetMinCountInternal(joltages, patternCosts, new Dictionary<int[], long>(new IntArrayEqualityComparer()));
|
||||
return res;
|
||||
|
||||
static long GetMinCountInternal(int[] targetJoltages, (int[] joltages, int cots)[] patternCosts, Dictionary<int[], long> memory)
|
||||
static long GetMinCountInternal(int[] targetJoltages, Dictionary<uint, (int[] joltages, int cots)[]> patternCosts, Dictionary<int[], long> memory)
|
||||
{
|
||||
if (targetJoltages.Min() < 0) return 1_000_000_000L;
|
||||
if (targetJoltages.All(j => j == 0)) return 0;
|
||||
if (memory.TryGetValue(targetJoltages, out var knownResult)) return knownResult;
|
||||
|
||||
var minCount = 1_000_000_000L;
|
||||
var patternsToCheck = patternCosts
|
||||
.Where(pc =>
|
||||
pc.joltages
|
||||
.Zip(targetJoltages, (pJolt, tJolt) => (pJolt % 2) == (tJolt % 2))
|
||||
.All(isEqual => isEqual))
|
||||
.ToArray();
|
||||
var joltageMask = GetMask(targetJoltages, level => level % 2 == 1);
|
||||
var patternsToCheck = patternCosts.GetValueOrDefault(joltageMask, []);
|
||||
foreach (var (joltageLevels, cost) in patternsToCheck)
|
||||
{
|
||||
var nextPattern = targetJoltages.Zip(joltageLevels, (jolts, level) => (jolts - level) / 2).ToArray();
|
||||
var resultNext = 2 * GetMinCountInternal(nextPattern, patternCosts, memory) + cost;
|
||||
if (resultNext < minCount)
|
||||
{
|
||||
minCount = resultNext;
|
||||
}
|
||||
minCount = Math.Min(minCount, resultNext);
|
||||
}
|
||||
|
||||
memory[targetJoltages] = minCount;
|
||||
|
|
@ -197,15 +193,16 @@ public class Day10 : IPuzzleSolver<long>
|
|||
}
|
||||
}
|
||||
|
||||
private IEnumerable<(int[], int)> GetPatternCosts(int patternLength, int[][] buttons)
|
||||
private IEnumerable<(uint, (int[], int))> GetPatternCosts(int patternLength, int[][] buttons)
|
||||
{
|
||||
yield return ([..Enumerable.Repeat(0, patternLength)], 0);
|
||||
yield return (0,([..Enumerable.Repeat(0, patternLength)], 0));
|
||||
for (var i = 1; i <= buttons.Length; i++)
|
||||
{
|
||||
foreach (var buttonPattern in buttons.Combinations(i))
|
||||
{
|
||||
var joltageLevels = GetJoltageLevelsForButtonPattern(patternLength, buttonPattern);
|
||||
yield return (joltageLevels, buttonPattern.Length);
|
||||
var mask = GetMask(joltageLevels, level => level % 2 == 1);
|
||||
yield return (mask,(joltageLevels, buttonPattern.Length));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,6 +222,9 @@ public class Day10 : IPuzzleSolver<long>
|
|||
return joltagesProduced;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint GetMask(int[] toBeMasked, Func<int, bool> maskPredicate) =>
|
||||
toBeMasked.Aggregate((uint)0L, (acc, val) => (acc << 1) | (uint)(maskPredicate(val) ? 1 : 0));
|
||||
|
||||
private long GetMinCountButtonPressesForJoltagesZ3(int[] joltages, int[][] buttons)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue