private static int NumberOfShortestCombinations(int[] list, int initialGoal) { var memo = new SimpleMemo <ulong>(); var lengths = new SafeDictionary <int, int>(); Explore(list.Length, 0, initialGoal); var shortestCombinations = lengths.OrderBy(x => x.Key).First().Value; return(shortestCombinations); void Explore(int size, uint pickmask, int goal) { if (goal == 0) { var len = pickmask.NumberOfSetBits(); lengths[len]++; return; } if (goal < 0 || size == 0) { return; } if (memo.IsSeenBefore((ulong)size << 32 | pickmask)) { return; } // For skipped item, pass 0 into the bit-mask (ie do nothing); for used item pass 1. Explore(size - 1, pickmask << 1, goal); Explore(size - 1, (pickmask << 1) + 1, goal - list[size - 1]); } }
protected override string Part2(string[] input) { var ids = input; // Instead of doing the trivial N^2 set of comparisons (where each comparison // would even need to step through all chars to find just one mismatch) do this: // For every string, remember n versions of it with each letter, one at a time, // swapped out with a dot. If we ever come across a similar string then we've // found the single-letter-mismatch. The result is the string except that dot // at the mismatched position - very nice. var seen = new SimpleMemo <string>(); foreach (var id in ids) { var letters = id.ToCharArray(); for (var i = 0; i < letters.Length; i++) { var tmp = letters[i]; letters[i] = '.'; var s = new string(letters); if (seen.IsSeenBefore(s)) { // We found the mismatch return(s.Replace(".", "")); } letters[i] = tmp; } } throw new Exception("Not found"); }
private static int FindFirstCycle(int[] banks) { var memo = new SimpleMemo <ulong>(); var cycle = 0; do { Redistribute(banks); cycle++; } while (!memo.IsSeenBefore(Hashing.KnuthHash(banks))); return(cycle); }
protected override int Part2(string[] input) { var deltas = input.Select(int.Parse).ToArray(); // Loop deltas to build frequency, until one is reached we've // seen before. Using while(true) + for() is faster than %. var seen = new SimpleMemo <int>(); var freq = 0; while (true) { foreach (var d in deltas) { freq += d; if (seen.IsSeenBefore(freq)) { return(freq); } } } }
protected override int Part1(string[] input) { var claims = ReadClaims(input); // Fastest way seem to be to simple hash memo-tables that register // every square and therefore can count the first time a square is // seen. It's faster than counting up all the overlappings and then // searching for those with >1 overlap. var once = new SimpleMemo <int>(); var twice = new SimpleMemo <int>(); var overlaps = 0; foreach (var pos in claims.SelectMany(c => c.Squares())) { if (once.IsSeenBefore(pos) && !twice.IsSeenBefore(pos)) { overlaps++; } } return(overlaps); }