657 lines
20 KiB
C++
657 lines
20 KiB
C++
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <deque>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <numeric>
|
|
#include <set>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#include "Array2D.h"
|
|
#include "Graph.h"
|
|
|
|
#define BIT(x) (1 << (x))
|
|
|
|
template <typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::vector<Args...>& container);
|
|
|
|
template <typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::deque<Args...>& container);
|
|
|
|
template <typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::set<Args...>& container);
|
|
|
|
template <typename T, typename S>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::map<T, S>& container);
|
|
|
|
template <typename T, typename S>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::pair<T, S>& pair);
|
|
|
|
template <typename Arg1, typename Arg2, typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::variant<Arg1, Arg2, Args...>& variant);
|
|
|
|
struct Helper
|
|
{
|
|
struct ScopedTraceErrorDisabler
|
|
{
|
|
ScopedTraceErrorDisabler();
|
|
~ScopedTraceErrorDisabler();
|
|
};
|
|
|
|
template <typename T, typename S>
|
|
static void RemoveIf(T& t, S func)
|
|
{
|
|
t.erase(std::remove_if(t.begin(), t.end(), func), t.end());
|
|
}
|
|
|
|
static std::vector<std::string_view> Split(const std::string& str, const std::string& delim);
|
|
static bool StartsWith(const std::string_view& str, const std::string& prefix, size_t offset = 0);
|
|
static bool EndsWith(const std::string_view& str, const std::string& prefix);
|
|
static void Replace(std::string& str, size_t size, const std::string& other, size_t pos);
|
|
|
|
static bool IsDigit(char c);
|
|
static int GetNumberOfDigits(int n);
|
|
static int GetNumberOfDigits(int64_t n);
|
|
static int64_t Pow10(int pow);
|
|
|
|
// Converts a binary string to an int32_t ie "10100111001" to 1337
|
|
static int BinStrToInt(const std::string& str);
|
|
|
|
// Converts a binary string to an int64_t ie "10100111001" to 1337
|
|
static int64_t BinStrToInt64(const std::string& str);
|
|
|
|
template <typename T, typename S>
|
|
static T Sum(const S& container)
|
|
{
|
|
return std::accumulate(container.begin(), container.end(), (T)0, std::plus<T>());
|
|
}
|
|
|
|
template <typename T, typename S, typename Container>
|
|
static T Sum(const Container& container, S func)
|
|
{
|
|
return std::accumulate(container.begin(), container.end(), (T)0, func);
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
static T Product(const S& container)
|
|
{
|
|
return std::accumulate(container.begin(), container.end(), (T)1, std::multiplies<T>());
|
|
}
|
|
|
|
template <typename T, typename S, typename Container>
|
|
static T Product(const Container& container, S func)
|
|
{
|
|
return std::accumulate(container.begin(), container.end(), (T)1, func);
|
|
}
|
|
|
|
template <typename Container>
|
|
static typename Container::value_type Min(const Container& container)
|
|
{
|
|
if (container.size() == 0)
|
|
{
|
|
std::cout << "Min: Container empty" << std::endl;
|
|
return typename Container::value_type{};
|
|
}
|
|
typename Container::value_type min = *container.begin();
|
|
for (auto&& element : container)
|
|
{
|
|
min = std::min(min, element);
|
|
}
|
|
return min;
|
|
}
|
|
|
|
template <typename Container>
|
|
static typename Container::value_type Max(const Container& container)
|
|
{
|
|
if (container.size() == 0)
|
|
{
|
|
std::cout << "Min: Container empty" << std::endl;
|
|
return typename Container::value_type{};
|
|
}
|
|
typename Container::value_type max = *container.begin();
|
|
for (auto&& element : container)
|
|
{
|
|
max = std::max(max, element);
|
|
}
|
|
return max;
|
|
}
|
|
|
|
template <typename T>
|
|
static T Sign(const T& t)
|
|
{
|
|
return t > 0 ? 1 : t < 0 ? -1 : 0;
|
|
}
|
|
|
|
template <typename T>
|
|
static std::set<T> GetUnion(const std::vector<std::set<T>>& list)
|
|
{
|
|
std::set<char> uniq;
|
|
for (auto l : list)
|
|
{
|
|
for (auto t : l)
|
|
{
|
|
uniq.emplace(t);
|
|
}
|
|
}
|
|
return uniq;
|
|
}
|
|
|
|
template <typename T>
|
|
static std::set<T> GetIntersection(const std::vector<std::set<T>>& list)
|
|
{
|
|
std::set<char> intersection = list[0];
|
|
|
|
for (size_t i = 1; i < list.size(); i++)
|
|
{
|
|
for (auto it = intersection.begin(); it != intersection.end();)
|
|
{
|
|
if (list[i].find(*it) == list[i].end())
|
|
it = intersection.erase(it);
|
|
else
|
|
it++;
|
|
}
|
|
}
|
|
return intersection;
|
|
}
|
|
|
|
template <typename T>
|
|
static std::set<T> GetIntersection(const std::set<T>& s1, const std::set<T>& s2)
|
|
{
|
|
std::set<T> intersection = s1;
|
|
|
|
for (auto it = intersection.begin(); it != intersection.end();)
|
|
{
|
|
if (s2.find(*it) == s2.end())
|
|
it = intersection.erase(it);
|
|
else
|
|
it++;
|
|
}
|
|
return intersection;
|
|
}
|
|
|
|
template <typename T>
|
|
static bool IsSubset(const std::set<T>& smallSet, const std::set<T>& bigSet)
|
|
{
|
|
if (bigSet.size() < smallSet.size())
|
|
return false;
|
|
|
|
for (auto&& t : smallSet)
|
|
{
|
|
if (bigSet.find(t) == bigSet.end())
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - initial state of the path finder
|
|
// Heuristic - int(Input, State)
|
|
// Given a state, what is the minimum cost to get to the goal
|
|
// state
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost
|
|
// to get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Heuristic, typename Branch, typename Goal>
|
|
static int AStar(const Input& input, const std::vector<State>& initial, Heuristic heuristic, Branch branch, Goal goal)
|
|
{
|
|
std::map<State, int> visited;
|
|
std::multimap<int, std::pair<int, State>> open;
|
|
for (int i = 0; i < initial.size(); i++)
|
|
open.emplace(0, std::pair<int, State>{0, initial[i]});
|
|
while (!open.empty())
|
|
{
|
|
auto it = open.begin();
|
|
if (goal(input, it->second.second))
|
|
{
|
|
return it->second.first;
|
|
}
|
|
int stateCost = it->second.first;
|
|
for (auto& newState : branch(input, it->second.second))
|
|
{
|
|
auto it = visited.find(newState.second);
|
|
int cost = stateCost + newState.first;
|
|
if (it == visited.end() || it->second > cost)
|
|
{
|
|
open.emplace(heuristic(input, newState.second) + cost, std::pair<int, State>{cost, newState.second});
|
|
visited.emplace(newState.second, cost);
|
|
}
|
|
}
|
|
open.erase(open.begin());
|
|
}
|
|
if (traceErrors)
|
|
std::cout << "No solution found" << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - initial state of the path finder
|
|
// Heuristic - int(Input, State)
|
|
// Given a state, what is the minimum cost to get to the goal
|
|
// state
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost
|
|
// to get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Heuristic, typename Branch, typename Goal>
|
|
static std::pair<int, std::vector<State>> AStarPath(
|
|
const Input& input, const std::vector<State>& initial, Heuristic heuristic, Branch branch, Goal goal)
|
|
{
|
|
std::map<State, int> visited;
|
|
std::multimap<int, std::pair<int, std::vector<State>>> open;
|
|
for (int i = 0; i < initial.size(); i++)
|
|
open.emplace(0, std::pair<int, std::vector<State>>{0, {initial[i]}});
|
|
while (!open.empty())
|
|
{
|
|
const auto& [heuristicVal, state] = *open.begin();
|
|
const auto& [cost, path] = state;
|
|
|
|
if (goal(input, path.back()))
|
|
return {cost, path};
|
|
|
|
for (const auto& [stateCost, newState] : branch(input, path.back()))
|
|
{
|
|
auto it = visited.find(newState);
|
|
int newCost = cost + stateCost;
|
|
if (it == visited.end() || it->second > cost)
|
|
{
|
|
auto newPath = path;
|
|
newPath.emplace_back(newState);
|
|
open.emplace(heuristic(input, newState) + newCost, std::pair<int, std::vector<State>>{newCost, newPath});
|
|
visited.emplace(newState, newCost);
|
|
}
|
|
}
|
|
open.erase(open.begin());
|
|
}
|
|
if (traceErrors)
|
|
std::cout << "No solution found" << std::endl;
|
|
return {0, {}};
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - initial state of the path finder
|
|
// Heuristic - int(Input, State)
|
|
// Given a state, what is the minimum cost to get to the goal
|
|
// state
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost
|
|
// to get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Heuristic, typename Branch, typename Goal>
|
|
static std::pair<int, std::vector<State>> AStarPath(
|
|
const Input& input, const State& initial, Heuristic heuristic, Branch branch, Goal goal)
|
|
{
|
|
return AStarPath(input, std::vector<State>{initial}, heuristic, branch, goal);
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - State of the path finder
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost to
|
|
// get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Branch, typename Goal>
|
|
static std::pair<int, std::vector<State>> DijkstrasPath(const Input& input,
|
|
const std::vector<State>& initial,
|
|
Branch branch,
|
|
Goal goal)
|
|
{
|
|
return AStarPath(input, initial, [](const Input&, const State&) { return 0; }, branch, goal);
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - State of the path finder
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost to
|
|
// get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Branch, typename Goal>
|
|
static std::pair<int, std::vector<State>> DijkstrasPath(const Input& input,
|
|
const State& initial,
|
|
Branch branch,
|
|
Goal goal)
|
|
{
|
|
return AStarPath(input, std::vector<State>{initial}, [](const Input&, const State&) { return 0; }, branch, goal);
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - State of the path finder
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost to
|
|
// get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Branch, typename Goal>
|
|
static std::set<State> DijkstrasAllVisited(const Input& input, const State& initial, Branch branch, Goal goal)
|
|
{
|
|
std::set<State> totalVisited;
|
|
int bestCost = std::numeric_limits<int>::max();
|
|
std::map<State, int> visited;
|
|
std::multimap<int, std::vector<State>> open;
|
|
open.emplace(0, std::vector{initial});
|
|
|
|
while (!open.empty())
|
|
{
|
|
const auto& [cost, path] = *open.begin();
|
|
if (cost > bestCost)
|
|
{
|
|
open.erase(open.begin());
|
|
continue;
|
|
}
|
|
|
|
if (goal(input, path.back()))
|
|
{
|
|
bestCost = cost;
|
|
for (const auto& state : path)
|
|
{
|
|
totalVisited.emplace(state);
|
|
}
|
|
open.erase(open.begin());
|
|
continue;
|
|
}
|
|
for (const auto& [newStateCost, newState] : branch(input, path.back()))
|
|
{
|
|
int newCost = cost + newStateCost;
|
|
auto it = visited.find(newState);
|
|
if (it == visited.end() || it->second >= newCost)
|
|
{
|
|
auto cpy = path;
|
|
cpy.emplace_back(newState);
|
|
open.emplace(newCost, cpy);
|
|
visited.emplace(newState, newCost);
|
|
}
|
|
}
|
|
open.erase(open.begin());
|
|
}
|
|
return totalVisited;
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - initial state of the path finder
|
|
// Heuristic - int(Input, State)
|
|
// Given a state, what is the minimum cost to get to the goal
|
|
// state
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost
|
|
// to get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Heuristic, typename Branch, typename Goal>
|
|
static int AStar(const Input& input, const State& initial, Heuristic heuristic, Branch branch, Goal goal)
|
|
{
|
|
return AStar(input, std::vector<State>{initial}, heuristic, branch, goal);
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - State of the path finder
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost to
|
|
// get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Branch, typename Goal>
|
|
static int Dijkstras(const Input& input, const std::vector<State>& initial, Branch branch, Goal goal)
|
|
{
|
|
return AStar(input, initial, [](const Input&, const State&) { return 0; }, branch, goal);
|
|
}
|
|
|
|
// Input - Puzzle input
|
|
// State - State of the path finder
|
|
// Branch - std::vector<std::pair<int, State>>(Input, State);
|
|
// Given a state, what are the possible next states and the cost to
|
|
// get to it
|
|
// Goal - bool(Input, State)
|
|
// Given a state, are we in the goal state
|
|
template <typename Input, typename State, typename Branch, typename Goal>
|
|
static int Dijkstras(const Input& input, const State& initial, Branch branch, Goal goal)
|
|
{
|
|
return AStar(input, std::vector<State>{initial}, [](const Input&, const State&) { return 0; }, branch, goal);
|
|
}
|
|
|
|
template <typename Container>
|
|
static std::ostream& Print(std::ostream& stream, const Container& container)
|
|
{
|
|
stream << '[';
|
|
int i = 0;
|
|
for (auto it = container.begin(); it != container.end(); ++it)
|
|
{
|
|
if (i != 0)
|
|
stream << ", ";
|
|
stream << *it;
|
|
i++;
|
|
}
|
|
stream << ']';
|
|
return stream;
|
|
}
|
|
|
|
static std::string Repeat(const std::string& str, int count);
|
|
|
|
template <typename T>
|
|
static std::vector<T> Repeat(const std::vector<T>& vec, int count)
|
|
{
|
|
std::vector<T> ret;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
for (const auto& t : vec)
|
|
{
|
|
ret.emplace_back(t);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static std::vector<std::string> GetAllRegexMatches(const std::string& str, const std::string& regex);
|
|
|
|
static std::vector<Index2D> GetNeighborDirections();
|
|
static Index2D GetDirection(char c);
|
|
|
|
// Solve for N:
|
|
// remainder1 = N % mod1
|
|
// remainder2 = N % mod2
|
|
static int64_t ChineseRemainderTheoremTwo(int64_t mod1, int64_t mod2, int64_t remainder1, int64_t remainder2);
|
|
|
|
// Solve for N:
|
|
// remainders = N % mods
|
|
static int64_t ChineseRemainderTheorem(const std::vector<int64_t>& mods, const std::vector<int64_t>& remainders);
|
|
|
|
// Solve for N:
|
|
// remainders = (start + N) % mods
|
|
static int64_t ChineseRemainderTheorem(const std::vector<int64_t>& mods,
|
|
std::vector<int64_t> remainders,
|
|
const std::vector<int64_t>& starts);
|
|
|
|
static uint64_t FastExponentiation(uint64_t start, uint64_t multiplication, uint64_t power, uint64_t mod);
|
|
|
|
// Input - Puzzle input
|
|
// Function - bool(int64_t);
|
|
// Given index, return whether the index should increase next
|
|
// iteration
|
|
//
|
|
// Returns the last index where Function returns true, or -1 if it never
|
|
// returns true
|
|
template <typename Input, typename Function>
|
|
static int64_t BinarySearch(const Input& input, int64_t min, int64_t max, Function func)
|
|
{
|
|
if (min >= max)
|
|
{
|
|
if (func(input, min))
|
|
return min;
|
|
else
|
|
return min - 1;
|
|
}
|
|
|
|
int i = min + (max - min) / 2;
|
|
if (func(input, i))
|
|
return BinarySearch(input, i + 1, max, func);
|
|
else
|
|
return BinarySearch(input, min, i - 1, func);
|
|
}
|
|
|
|
static int64_t ManhattanDistance(const Index2D& from, const Index2D& to);
|
|
|
|
static void DisableTraceErrors();
|
|
|
|
static void ResetTraceErrors();
|
|
|
|
private:
|
|
template <typename Key, typename Value>
|
|
static Value TSPCalculatePath(const Graph<Key, Value>& graph, const std::vector<Key>& path, bool returnToStart)
|
|
{
|
|
int cost = 0;
|
|
for (int i = 0; i < path.size() - 1; i++)
|
|
{
|
|
cost += graph.GetEdge(path[i], path[i + 1]);
|
|
}
|
|
|
|
if (returnToStart)
|
|
cost += graph.GetEdge(path.back(), path.front());
|
|
|
|
return cost;
|
|
}
|
|
|
|
template <typename Key, typename Value>
|
|
static int TSP(const Graph<Key, Value>& graph,
|
|
const std::set<Key>& nodesLeft,
|
|
const std::vector<Key>& order,
|
|
bool returnToStart)
|
|
{
|
|
if (nodesLeft.empty())
|
|
return TSPCalculatePath(graph, order, returnToStart);
|
|
|
|
bool hasSet = false;
|
|
Value tsp;
|
|
|
|
for (auto& node : nodesLeft)
|
|
{
|
|
std::set<Key> newNodesLeft = nodesLeft;
|
|
newNodesLeft.erase(node);
|
|
std::vector<Key> newOrder = order;
|
|
newOrder.emplace_back(node);
|
|
if (hasSet)
|
|
tsp = std::min(tsp, TSP(graph, newNodesLeft, newOrder, returnToStart));
|
|
else
|
|
tsp = TSP(graph, newNodesLeft, newOrder, returnToStart);
|
|
hasSet = true;
|
|
}
|
|
return tsp;
|
|
}
|
|
|
|
public:
|
|
// Key - Node type of the graph
|
|
// Value - Edge type of the graph
|
|
template <typename Key, typename Value>
|
|
static int TSP(const Graph<Key, Value>& graph, const Key& start, bool returnToStart)
|
|
{
|
|
std::set<Key> nodes = graph.GetNodes();
|
|
nodes.erase(nodes.find(start));
|
|
return TSP(graph, nodes, std::vector<Key>{start}, returnToStart);
|
|
}
|
|
|
|
// Key - Node type of the graph
|
|
// Value - Edge type of the graph
|
|
template <typename Key, typename Value>
|
|
static int TSP(const Graph<Key, Value>& graph, bool returnToStart)
|
|
{
|
|
return TSP(graph, graph.GetNodes(), std::vector<Key>{}, returnToStart);
|
|
}
|
|
|
|
static bool traceErrors;
|
|
};
|
|
|
|
template <typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::vector<Args...>& container)
|
|
{
|
|
return Helper::Print(stream, container);
|
|
}
|
|
|
|
template <typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::deque<Args...>& container)
|
|
{
|
|
return Helper::Print(stream, container);
|
|
}
|
|
|
|
template <typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::set<Args...>& container)
|
|
{
|
|
return Helper::Print(stream, container);
|
|
}
|
|
|
|
template <typename T, size_t N>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::array<T, N>& container)
|
|
{
|
|
return Helper::Print(stream, container);
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::map<T, S>& container)
|
|
{
|
|
stream << "{";
|
|
int i = 0;
|
|
for (const auto& [t, s] : container)
|
|
{
|
|
if (i != 0)
|
|
stream << ", ";
|
|
stream << t << " => " << s;
|
|
i++;
|
|
}
|
|
stream << "}";
|
|
return stream;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::multimap<T, S>& container)
|
|
{
|
|
stream << "{";
|
|
int i = 0;
|
|
for (const auto& [t, s] : container)
|
|
{
|
|
if (i != 0)
|
|
stream << ", ";
|
|
stream << t << " => " << s;
|
|
i++;
|
|
}
|
|
stream << "}";
|
|
return stream;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::unordered_map<T, S>& container)
|
|
{
|
|
stream << "{";
|
|
int i = 0;
|
|
for (const auto& [t, s] : container)
|
|
{
|
|
if (i != 0)
|
|
stream << ", ";
|
|
stream << t << " => " << s;
|
|
i++;
|
|
}
|
|
stream << "}";
|
|
return stream;
|
|
}
|
|
|
|
template <typename T, typename S>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::pair<T, S>& pair)
|
|
{
|
|
return stream << "(" << pair.first << ", " << pair.second << ")";
|
|
}
|
|
|
|
template <typename Arg1, typename Arg2, typename... Args>
|
|
static std::ostream& operator<<(std::ostream& stream, const std::variant<Arg1, Arg2, Args...>& variant)
|
|
{
|
|
std::visit([&stream](const auto& value) { stream << value; }, variant);
|
|
return stream;
|
|
}
|