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;
|
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))
|
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)
|
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()));
|
var res = GetMinCountInternal(joltages, patternCosts, new Dictionary<int[], long>(new IntArrayEqualityComparer()));
|
||||||
return res;
|
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 (targetJoltages.All(j => j == 0)) return 0;
|
||||||
if (memory.TryGetValue(targetJoltages, out var knownResult)) return knownResult;
|
if (memory.TryGetValue(targetJoltages, out var knownResult)) return knownResult;
|
||||||
|
|
||||||
var minCount = 1_000_000_000L;
|
var minCount = 1_000_000_000L;
|
||||||
var patternsToCheck = patternCosts
|
var joltageMask = GetMask(targetJoltages, level => level % 2 == 1);
|
||||||
.Where(pc =>
|
var patternsToCheck = patternCosts.GetValueOrDefault(joltageMask, []);
|
||||||
pc.joltages
|
|
||||||
.Zip(targetJoltages, (pJolt, tJolt) => (pJolt % 2) == (tJolt % 2))
|
|
||||||
.All(isEqual => isEqual))
|
|
||||||
.ToArray();
|
|
||||||
foreach (var (joltageLevels, cost) in patternsToCheck)
|
foreach (var (joltageLevels, cost) in patternsToCheck)
|
||||||
{
|
{
|
||||||
var nextPattern = targetJoltages.Zip(joltageLevels, (jolts, level) => (jolts - level) / 2).ToArray();
|
var nextPattern = targetJoltages.Zip(joltageLevels, (jolts, level) => (jolts - level) / 2).ToArray();
|
||||||
var resultNext = 2 * GetMinCountInternal(nextPattern, patternCosts, memory) + cost;
|
var resultNext = 2 * GetMinCountInternal(nextPattern, patternCosts, memory) + cost;
|
||||||
if (resultNext < minCount)
|
minCount = Math.Min(minCount, resultNext);
|
||||||
{
|
|
||||||
minCount = resultNext;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memory[targetJoltages] = minCount;
|
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++)
|
for (var i = 1; i <= buttons.Length; i++)
|
||||||
{
|
{
|
||||||
foreach (var buttonPattern in buttons.Combinations(i))
|
foreach (var buttonPattern in buttons.Combinations(i))
|
||||||
{
|
{
|
||||||
var joltageLevels = GetJoltageLevelsForButtonPattern(patternLength, buttonPattern);
|
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;
|
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)
|
private long GetMinCountButtonPressesForJoltagesZ3(int[] joltages, int[][] buttons)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue