Add solution for "Day 16: Reindeer Maze", part 1
This commit is contained in:
parent
a819caba8b
commit
08a94ba068
45
include/aoc/ReindeerMaze.hpp
Normal file
45
include/aoc/ReindeerMaze.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <aoc/LinesSolver.hpp>
|
||||
#include <aoc/ReindeerMazeCrossing.hpp>
|
||||
#include <aoc/ReindeerMazePathIncidence.hpp>
|
||||
#include <aoc/WeightedEdgeGraph.hpp>
|
||||
|
||||
class ReindeerMaze
|
||||
: public LinesSolver
|
||||
{
|
||||
public:
|
||||
ReindeerMaze(const int inputFileNameSuffix = 0);
|
||||
virtual const std::string getPuzzleName() const override;
|
||||
virtual const int getPuzzleDay() const override;
|
||||
virtual void finish() override;
|
||||
private:
|
||||
static constexpr char getStartChar();
|
||||
static constexpr char getEndChar();
|
||||
static constexpr char getWallChar();
|
||||
static constexpr int getTurnCost();
|
||||
void initializeWorkList(std::list<ReindeerMazeCrossing>& crossings, const int entryVertex);
|
||||
void addCheckedIncidence(std::vector<ReindeerMazePathIncidence>& incidences, const Point2 start,
|
||||
const Point2 direction);
|
||||
Point2 findStart();
|
||||
void AddPathSegmentEdges(WeightedEdgeGraph& graph, const ReindeerMazePathIncidence& pathIncidence,
|
||||
const std::vector<ReindeerMazePathIncidence>& otherPathIncidences);
|
||||
};
|
32
include/aoc/ReindeerMazeCrossing.hpp
Normal file
32
include/aoc/ReindeerMazeCrossing.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <aoc/Point2.hpp>
|
||||
#include <aoc/ReindeerMazePathIncidence.hpp>
|
||||
|
||||
class ReindeerMazeCrossing
|
||||
{
|
||||
public:
|
||||
ReindeerMazeCrossing(const Point2 position);
|
||||
Point2 getPosition() const;
|
||||
bool isFinished() const;
|
||||
std::vector<ReindeerMazePathIncidence> incidences;
|
||||
private:
|
||||
Point2 position_;
|
||||
};
|
34
include/aoc/ReindeerMazePathIncidence.hpp
Normal file
34
include/aoc/ReindeerMazePathIncidence.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aoc/Point2.hpp>
|
||||
|
||||
class ReindeerMazePathIncidence
|
||||
{
|
||||
public:
|
||||
ReindeerMazePathIncidence(const Point2 direction);
|
||||
ReindeerMazePathIncidence(const Point2 direction, const int pathVertex);
|
||||
Point2 getDirection() const;
|
||||
int getPathVertex() const;
|
||||
void setPathVertex(const int pathVertex);
|
||||
int getPathCost() const;
|
||||
void setPathCost(const int pathCost);
|
||||
private:
|
||||
Point2 direction_;
|
||||
int pathVertex_;
|
||||
int pathCost_;
|
||||
};
|
28
include/aoc/VertexEdgeIncidence.hpp
Normal file
28
include/aoc/VertexEdgeIncidence.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
class VertexEdgeIncidence
|
||||
{
|
||||
public:
|
||||
VertexEdgeIncidence(const int vertex, const int next)
|
||||
{
|
||||
this->vertex = vertex;
|
||||
this->next = next;
|
||||
}
|
||||
int vertex;
|
||||
int next;
|
||||
};
|
33
include/aoc/WeightedEdgeGraph.hpp
Normal file
33
include/aoc/WeightedEdgeGraph.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <aoc/VertexEdgeIncidence.hpp>
|
||||
|
||||
class WeightedEdgeGraph
|
||||
{
|
||||
public:
|
||||
WeightedEdgeGraph();
|
||||
int addVertex();
|
||||
void addEdge(const int vertex1, const int vertex2, const int weight);
|
||||
int dijkstra(const int source, const int target) const;
|
||||
private:
|
||||
std::vector<int> firstVertexIncidences_;
|
||||
std::vector<VertexEdgeIncidence> vertexEdgeIncidences_;
|
||||
std::vector<int> edgeWeights_;
|
||||
};
|
@ -36,6 +36,7 @@
|
||||
#include <aoc/ClawContraption.hpp>
|
||||
#include <aoc/RestroomRedoubt.hpp>
|
||||
#include <aoc/WarehouseWoes.hpp>
|
||||
#include <aoc/ReindeerMaze.hpp>
|
||||
#include <aoc/LanParty.hpp>
|
||||
|
||||
void Program::run()
|
||||
@ -69,6 +70,7 @@ void Program::runSolvers()
|
||||
runSolver<ClawContraption>(solverEngine);
|
||||
runSolver<RestroomRedoubt>(solverEngine);
|
||||
runSolver<WarehouseWoes>(solverEngine);
|
||||
runSolver<ReindeerMaze>(solverEngine);
|
||||
runSolver<LanParty>(solverEngine);
|
||||
}
|
||||
|
||||
|
258
src/ReindeerMaze.cpp
Normal file
258
src/ReindeerMaze.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <aoc/ReindeerMaze.hpp>
|
||||
|
||||
ReindeerMaze::ReindeerMaze(const int inputFileNameSuffix)
|
||||
: LinesSolver{ inputFileNameSuffix }
|
||||
{
|
||||
}
|
||||
|
||||
const std::string ReindeerMaze::getPuzzleName() const
|
||||
{
|
||||
return "Reindeer Maze";
|
||||
}
|
||||
|
||||
const int ReindeerMaze::getPuzzleDay() const
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
void ReindeerMaze::finish()
|
||||
{
|
||||
// Initializes the graph of path segment incidences.
|
||||
WeightedEdgeGraph graph{};
|
||||
auto entry = graph.addVertex();
|
||||
auto exit = graph.addVertex();
|
||||
|
||||
// Uses list for work items to prevent invalidation of iterators on add.
|
||||
std::list<ReindeerMazeCrossing> crossings{};
|
||||
initializeWorkList(crossings, entry);
|
||||
|
||||
while (!crossings.empty())
|
||||
{
|
||||
auto startCrossing{ --crossings.end() };
|
||||
Point2 startPosition = startCrossing->getPosition();
|
||||
auto incidence = std::find_if(startCrossing->incidences.begin(), startCrossing->incidences.end(),
|
||||
[](auto& x) { return x.getPathVertex() == -1; });
|
||||
Point2 direction{ incidence->getDirection() };
|
||||
Point2 backwards{ -direction };
|
||||
Point2 position{ startPosition + direction };
|
||||
|
||||
int pathCost{ 1 };
|
||||
bool isSkipped{ false };
|
||||
|
||||
int nNext{ 0 };
|
||||
while (getCharAt(position) != getEndChar() &&
|
||||
std::find_if(crossings.begin(), crossings.end(),
|
||||
[position](auto& x) { return x.getPosition() == position; }) == crossings.end())
|
||||
{
|
||||
nNext = 0;
|
||||
Point2 nextPosition, nextDirection;
|
||||
for (const auto& checkDirection : Point2::cardinalDirections)
|
||||
{
|
||||
if (checkDirection != backwards)
|
||||
{
|
||||
Point2 checkPosition{ checkDirection + position };
|
||||
if (getCharAt(checkPosition) != getWallChar())
|
||||
{
|
||||
nNext++;
|
||||
if (nNext == 1)
|
||||
{
|
||||
// Found a possible next step.
|
||||
nextPosition = checkPosition;
|
||||
nextDirection = checkDirection;
|
||||
}
|
||||
else if (nNext == 2)
|
||||
{
|
||||
// Found a second possible step, i.e. a new crossing. Will stop processing this path
|
||||
// segment.
|
||||
crossings.emplace_back(position);
|
||||
crossings.back().incidences.emplace_back(backwards);
|
||||
crossings.back().incidences.emplace_back(nextDirection);
|
||||
crossings.back().incidences.emplace_back(checkDirection);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Found another possible step. Adds the incidence to the new crossing.
|
||||
crossings.back().incidences.emplace_back(checkDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nNext == 1)
|
||||
{
|
||||
position = nextPosition;
|
||||
pathCost++;
|
||||
if (direction != nextDirection)
|
||||
{
|
||||
pathCost += getTurnCost();
|
||||
direction = nextDirection;
|
||||
backwards = -direction;
|
||||
}
|
||||
|
||||
if (position == startPosition)
|
||||
{
|
||||
// Stops processing this path segment because it is a loop, and remove both incidences from the
|
||||
// start crossing. Both must exist here.
|
||||
startCrossing->incidences.erase(incidence);
|
||||
auto endIncidence = std::find_if(startCrossing->incidences.begin(), startCrossing->incidences.end(),
|
||||
[backwards](auto& x) { return x.getDirection() == backwards; });
|
||||
startCrossing->incidences.erase(endIncidence);
|
||||
isSkipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (nNext == 0)
|
||||
{
|
||||
// Stops processing this path segment because it is a dead-end, and remove it from the start crossing.
|
||||
startCrossing->incidences.erase(incidence);
|
||||
isSkipped = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stops processing this path segment because a new crossing has been found. This check avoids the
|
||||
// find_if() call in the loop condition.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSkipped)
|
||||
{
|
||||
// Adds the new maze path segment as a vertex.
|
||||
auto pathVertex = graph.addVertex();
|
||||
|
||||
// Updates start crossing.
|
||||
incidence->setPathVertex(pathVertex);
|
||||
incidence->setPathCost(pathCost);
|
||||
|
||||
// Determines the end crossing of the new path segment and its incidence.
|
||||
std::list<ReindeerMazeCrossing>::iterator endCrossing;
|
||||
std::vector<ReindeerMazePathIncidence>::iterator endIncidence;
|
||||
endCrossing = nNext == 1
|
||||
? endCrossing = std::find_if(crossings.begin(), crossings.end(),
|
||||
[position](auto& x) { return x.getPosition() == position; })
|
||||
: --crossings.end();
|
||||
if (endCrossing != crossings.end())
|
||||
{
|
||||
// This incidence must exist, no need to check the incidence iterator.
|
||||
endIncidence = std::find_if(endCrossing->incidences.begin(), endCrossing->incidences.end(),
|
||||
[backwards](auto& x) { return x.getDirection() == backwards; });
|
||||
endIncidence->setPathVertex(pathVertex);
|
||||
endIncidence->setPathCost(pathCost);
|
||||
}
|
||||
|
||||
// Connects the new path segment to all adjacent path segments.
|
||||
AddPathSegmentEdges(graph, *incidence, startCrossing->incidences);
|
||||
if (endCrossing != crossings.end())
|
||||
{
|
||||
AddPathSegmentEdges(graph, *endIncidence, endCrossing->incidences);
|
||||
}
|
||||
else
|
||||
{
|
||||
graph.addEdge(pathVertex, exit, pathCost);
|
||||
}
|
||||
|
||||
// Checks if end crossing is finished.
|
||||
//checkFinishedCrossing(crossings, endCrossing);
|
||||
if (endCrossing != crossings.end() && endCrossing->isFinished())
|
||||
{
|
||||
crossings.erase(endCrossing);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if start crossing is finished.
|
||||
if (startCrossing->isFinished())
|
||||
{
|
||||
crossings.erase(startCrossing);
|
||||
}
|
||||
}
|
||||
|
||||
part1 = graph.dijkstra(entry, exit) / 2;
|
||||
}
|
||||
|
||||
constexpr char ReindeerMaze::getStartChar()
|
||||
{
|
||||
return 'S';
|
||||
}
|
||||
|
||||
constexpr char ReindeerMaze::getEndChar()
|
||||
{
|
||||
return 'E';
|
||||
}
|
||||
|
||||
constexpr char ReindeerMaze::getWallChar()
|
||||
{
|
||||
return '#';
|
||||
}
|
||||
|
||||
constexpr int ReindeerMaze::getTurnCost()
|
||||
{
|
||||
return 1000;
|
||||
}
|
||||
|
||||
// Initializes the work list of crossing incidences.
|
||||
void ReindeerMaze::initializeWorkList(std::list<ReindeerMazeCrossing>& crossings, const int entryVertex)
|
||||
{
|
||||
Point2 start{ findStart() };
|
||||
crossings.emplace_back(start);
|
||||
crossings.back().incidences.emplace_back(Point2::left, entryVertex);
|
||||
addCheckedIncidence(crossings.back().incidences, start, Point2::right);
|
||||
addCheckedIncidence(crossings.back().incidences, start, Point2::up);
|
||||
}
|
||||
|
||||
void ReindeerMaze::addCheckedIncidence(std::vector<ReindeerMazePathIncidence>& incidences, const Point2 start,
|
||||
const Point2 direction)
|
||||
{
|
||||
if (getCharAt(start + direction) != getWallChar())
|
||||
{
|
||||
incidences.emplace_back(direction);
|
||||
}
|
||||
}
|
||||
|
||||
Point2 ReindeerMaze::findStart()
|
||||
{
|
||||
for (int j = 0; j < lines.size(); j++)
|
||||
{
|
||||
for (int i = 0; i < lines[j].size(); i++)
|
||||
{
|
||||
if (lines[j][i] == getStartChar())
|
||||
{
|
||||
return { i, j };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
void ReindeerMaze::AddPathSegmentEdges(WeightedEdgeGraph& graph, const ReindeerMazePathIncidence& pathIncidence,
|
||||
const std::vector<ReindeerMazePathIncidence>& otherPathIncidences)
|
||||
{
|
||||
for (auto& otherIncidence : otherPathIncidences)
|
||||
{
|
||||
if (otherIncidence.getPathVertex() > -1 && otherIncidence.getPathVertex() != pathIncidence.getPathVertex())
|
||||
{
|
||||
int weight{ pathIncidence.getPathCost() + otherIncidence.getPathCost() };
|
||||
// Checks for turn, i.e. perpendicular directions.
|
||||
if (otherIncidence.getDirection().x != -pathIncidence.getDirection().x)
|
||||
{
|
||||
weight += 2 * getTurnCost();
|
||||
}
|
||||
graph.addEdge(pathIncidence.getPathVertex(), otherIncidence.getPathVertex(), weight);
|
||||
}
|
||||
}
|
||||
}
|
32
src/ReindeerMazeCrossing.cpp
Normal file
32
src/ReindeerMazeCrossing.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <aoc/ReindeerMazeCrossing.hpp>
|
||||
|
||||
ReindeerMazeCrossing::ReindeerMazeCrossing(const Point2 position)
|
||||
: position_{ position }, incidences{}
|
||||
{
|
||||
}
|
||||
|
||||
Point2 ReindeerMazeCrossing::getPosition() const
|
||||
{
|
||||
return position_;
|
||||
}
|
||||
|
||||
bool ReindeerMazeCrossing::isFinished() const
|
||||
{
|
||||
return std::find_if(incidences.begin(), incidences.end(), [](auto& x) { return x.getPathVertex() < 0; }) ==
|
||||
incidences.end();
|
||||
}
|
51
src/ReindeerMazePathIncidence.cpp
Normal file
51
src/ReindeerMazePathIncidence.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <aoc/ReindeerMazePathIncidence.hpp>
|
||||
|
||||
ReindeerMazePathIncidence::ReindeerMazePathIncidence(const Point2 direction)
|
||||
: ReindeerMazePathIncidence(direction, -1)
|
||||
{
|
||||
}
|
||||
|
||||
ReindeerMazePathIncidence::ReindeerMazePathIncidence(const Point2 direction, const int pathVertex)
|
||||
: direction_{ direction }, pathVertex_{ pathVertex }, pathCost_{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
Point2 ReindeerMazePathIncidence::getDirection() const
|
||||
{
|
||||
return direction_;
|
||||
}
|
||||
|
||||
int ReindeerMazePathIncidence::getPathVertex() const
|
||||
{
|
||||
return pathVertex_;
|
||||
}
|
||||
|
||||
void ReindeerMazePathIncidence::setPathVertex(const int pathVertex)
|
||||
{
|
||||
pathVertex_ = pathVertex;
|
||||
}
|
||||
|
||||
int ReindeerMazePathIncidence::getPathCost() const
|
||||
{
|
||||
return pathCost_;
|
||||
}
|
||||
|
||||
void ReindeerMazePathIncidence::setPathCost(const int pathCost)
|
||||
{
|
||||
pathCost_ = pathCost;
|
||||
}
|
70
src/WeightedEdgeGraph.cpp
Normal file
70
src/WeightedEdgeGraph.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
// Solutions to the Advent Of Code 2024.
|
||||
// Copyright (C) 2025 Stefan Müller
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify it under
|
||||
// the terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include <aoc/WeightedEdgeGraph.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
|
||||
WeightedEdgeGraph::WeightedEdgeGraph()
|
||||
: firstVertexIncidences_{}, vertexEdgeIncidences_{}, edgeWeights_{}
|
||||
{
|
||||
}
|
||||
|
||||
int WeightedEdgeGraph::addVertex()
|
||||
{
|
||||
firstVertexIncidences_.push_back(-1);
|
||||
return (int)firstVertexIncidences_.size() - 1;
|
||||
}
|
||||
|
||||
void WeightedEdgeGraph::addEdge(const int vertex1, const int vertex2, const int weight)
|
||||
{
|
||||
vertexEdgeIncidences_.emplace_back(vertex2, firstVertexIncidences_[vertex1]);
|
||||
firstVertexIncidences_[vertex1] = (int)vertexEdgeIncidences_.size() - 1;
|
||||
vertexEdgeIncidences_.emplace_back(vertex1, firstVertexIncidences_[vertex2]);
|
||||
firstVertexIncidences_[vertex2] = (int)vertexEdgeIncidences_.size() - 1;
|
||||
edgeWeights_.push_back(weight);
|
||||
}
|
||||
|
||||
int WeightedEdgeGraph::dijkstra(const int source, const int target) const
|
||||
{
|
||||
std::vector<int> distances(firstVertexIncidences_.size(), std::numeric_limits<int>::max());
|
||||
auto compare = [&distances](int left, int right) { return distances[left] > distances[right]; };
|
||||
std::priority_queue<int, std::vector<int>, decltype(compare)> queue{ compare };
|
||||
|
||||
distances[source] = 0;
|
||||
queue.push(source);
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
int v{ queue.top() };
|
||||
queue.pop();
|
||||
|
||||
int incidence{ firstVertexIncidences_[v] };
|
||||
while (incidence > -1)
|
||||
{
|
||||
int neighbor{ vertexEdgeIncidences_[incidence].vertex };
|
||||
int newDistance{ distances[v] + edgeWeights_[incidence >> 1] };
|
||||
if (distances[neighbor] > newDistance)
|
||||
{
|
||||
distances[neighbor] = newDistance;
|
||||
queue.push(neighbor);
|
||||
}
|
||||
incidence = vertexEdgeIncidences_[incidence].next;
|
||||
}
|
||||
}
|
||||
|
||||
return distances[target];
|
||||
}
|
@ -33,6 +33,7 @@
|
||||
#include <aoc/ClawContraption.hpp>
|
||||
#include <aoc/RestroomRedoubt.hpp>
|
||||
#include <aoc/WarehouseWoes.hpp>
|
||||
#include <aoc/ReindeerMaze.hpp>
|
||||
#include <aoc/LanParty.hpp>
|
||||
|
||||
#define REQUIRE_MESSAGE(cond, msg) if (!(cond)) { INFO(msg); REQUIRE(cond); }
|
||||
@ -252,6 +253,23 @@ TEST_CASE("[WarehouseWoesTests]")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[ReindeerMazeTests]")
|
||||
{
|
||||
TestContext test;
|
||||
SECTION("FullData")
|
||||
{
|
||||
test.run(std::make_unique<ReindeerMaze>(), 72400, 0, test.getInputPaths());
|
||||
}
|
||||
SECTION("ExampleData")
|
||||
{
|
||||
test.run(std::make_unique<ReindeerMaze>(), 7036, 0, test.getExampleInputPaths());
|
||||
}
|
||||
SECTION("ExampleData2")
|
||||
{
|
||||
test.run(std::make_unique<ReindeerMaze>(2), 11048, 0, test.getExampleInputPaths());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[LanPartyTests]")
|
||||
{
|
||||
TestContext test;
|
||||
|
Loading…
x
Reference in New Issue
Block a user