Terrible, awful day 13 solution
This commit is contained in:
2
13input.txt
Normal file
2
13input.txt
Normal 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
|
@ -47,6 +47,9 @@
|
||||
<None Update="12input.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="13input.txt">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -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
171
Q13.cs
Normal 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}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user