Terrible, awful day 13 solution

This commit is contained in:
2020-12-13 12:09:23 -06:00
parent 5defd6ff60
commit ff5f16be28
4 changed files with 177 additions and 0 deletions

2
13input.txt Normal file
View File

@ -0,0 +1,2 @@
1000299
41,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,37,x,x,x,x,x,971,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,17,13,x,x,x,x,23,x,x,x,x,x,29,x,487,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,19

View File

@ -47,6 +47,9 @@
<None Update="12input.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="13input.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -17,6 +17,7 @@
Q10.Go();
Q11.Go();
Q12.Go();
Q13.Go();
Util.Log($"Total time={(System.DateTime.Now - start).TotalMilliseconds}ms");
}
}

171
Q13.cs Normal file
View File

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace _2020
{
class Q13
{
static int leaveTime;
static List<int> busses = new List<int>();
public static void Go()
{
var start = DateTime.Now;
MakeList();
Util.Log($"Q13 MakeList took {(DateTime.Now - start).TotalMilliseconds}ms");
var p1start = DateTime.Now;
Part1();
Util.Log($"Q13 part1 took {(DateTime.Now - p1start).TotalMilliseconds}ms");
var p2start = DateTime.Now;
Part2();
Util.Log($"Q13 part2 took {(DateTime.Now - p2start).TotalMilliseconds}ms");
Util.Log($"Q13 took {(DateTime.Now - start).TotalMilliseconds}ms");
}
static void MakeList()
{
var lines = File.ReadAllLines("13input.txt");
if (lines.Length != 2)
{
throw new Exception("Invalid input");
}
leaveTime = Convert.ToInt32(lines[0]);
foreach (var bus in lines[1].Split(','))
{
if (bus == "x")
{
busses.Add(-1);
continue;
}
busses.Add(Convert.ToInt32(bus));
}
}
static void Part1()
{
int smallestModulo = int.MaxValue;
int smallestBus = -1;
foreach (var bus in busses)
{
if (bus < 0)
{
continue;
}
var mod = bus - (leaveTime % bus);
if (mod < smallestModulo)
{
smallestModulo = mod;
smallestBus = bus;
}
}
Util.Log($"Q13Part1: soonest bus={smallestBus}, departs={leaveTime + smallestModulo}, wait time={smallestModulo}m, answer={smallestBus * smallestModulo}");
}
// taken from https://rosettacode.org/wiki/Chinese_remainder_theorem#C.23, modified for int64s. i don't know how this works. who am i, sun-tzu?
static long GetChineseRemainderTheorem(IEnumerable<int> n, IEnumerable<int> a)
{
long prod = n.Aggregate(1L, (i, j) => i * j);
long p;
long sm = 0;
for (int i = 0; i < n.Count(); i++)
{
p = prod / n.ElementAt(i);
sm += a.ElementAt(i) * ModularMultiplicativeInverse(p, n.ElementAt(i)) * p;
}
return sm % prod;
}
static long ModularMultiplicativeInverse(long a, long mod)
{
long b = a % mod;
for (long x = 1; x < mod; x++)
{
if ((b * x) % mod == 1)
{
return x;
}
}
return 1;
}
static void Part2()
{
var a = new List<int>();
var n = new List<int>();
for (int i = 0; i < busses.Count; i++)
{
if (busses[i] <= 0)
{
continue;
}
a.Add(busses[i] - i % busses[i]);
n.Add(busses[i]);
}
Util.Log($"Q13Part2: val={GetChineseRemainderTheorem(n, a)}");
}
// this is how i initially solved it. took ~30mins. i'm not proud of it, but the "real" answer apparently required specialized knowledge i did not have.
static void Part2BruteForce()
{
int root = busses.First(x => x > 0);
var sorted = busses.OrderBy(x => x);
var largest = sorted.Last();
long checkVal = 0;
var idx = busses.IndexOf(largest);
int answersFound = 0;
int numThreads = 13;
Parallel.For(0, numThreads, thread =>
{
var threadVal = checkVal + (thread * largest);
long rootCheckVal = 0;
while (answersFound == 0)
{
threadVal += numThreads * largest;
rootCheckVal = threadVal - idx;
if (rootCheckVal % root == 0)
{
var gotit = false;
for (int i = 1; i < busses.Count; i++)
{
if (busses[i] <= 0)
{
continue;
}
if ((rootCheckVal + i) % busses[i] == 0)
{
gotit = true;
}
else
{
gotit = false;
break;
}
}
if (gotit)
{
Interlocked.Increment(ref answersFound);
break;
}
}
}
Util.Log($"Q13Part2: val={rootCheckVal}");
});
}
}
}