Add solution for "Day 23: LAN Party", part 2
This commit is contained in:
@@ -15,6 +15,9 @@
|
||||
|
||||
#include <aoc/LanParty.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
const std::string LanParty::getPuzzleName() const
|
||||
{
|
||||
return "LAN Party";
|
||||
@@ -32,12 +35,29 @@ void LanParty::processDataLine(const std::string& line)
|
||||
|
||||
void LanParty::finish()
|
||||
{
|
||||
size_t targetCliqueNumber{ 0 };
|
||||
auto itTx = labelMap_.lower_bound(getFirstTxComputerName());
|
||||
const auto itTxEnd = labelMap_.upper_bound(getLastTxComputerName());
|
||||
while (itTx != itTxEnd)
|
||||
{
|
||||
computeInterconnectedThreeSetCount(itTx->second);
|
||||
itTx++;
|
||||
targetCliqueNumber = std::max(targetCliqueNumber, lan_.getDegree(itTx->second));
|
||||
++itTx;
|
||||
}
|
||||
|
||||
// Assumes that the graph is connected, but not complete. Otherwise we would start with targetCliqueNumber + 1.
|
||||
// Also assumes that the clique number of the graph is close to its maximum degree, hence starting with a large
|
||||
// target number.
|
||||
bool isFound{ false };
|
||||
while (!isFound && targetCliqueNumber > 2)
|
||||
{
|
||||
auto itTx = labelMap_.lower_bound(getFirstTxComputerName());
|
||||
while (!isFound && itTx != itTxEnd)
|
||||
{
|
||||
isFound = findCompleteSubgraph(itTx->second, targetCliqueNumber);
|
||||
++itTx;
|
||||
}
|
||||
--targetCliqueNumber;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,20 +94,20 @@ void LanParty::computeInterconnectedThreeSetCount(const int vertexTx)
|
||||
if (canProcessVertex(itFirstNeighbor->vertex, vertexTx))
|
||||
{
|
||||
auto itSecondNeighbor = itFirstNeighbor;
|
||||
itSecondNeighbor++;
|
||||
++itSecondNeighbor;
|
||||
while (itSecondNeighbor != lan_.end())
|
||||
{
|
||||
if (canProcessVertex(itSecondNeighbor->vertex, vertexTx))
|
||||
{
|
||||
if (lan_.areAdjacent(itFirstNeighbor->vertex, itSecondNeighbor->vertex))
|
||||
{
|
||||
part1++;
|
||||
++part1;
|
||||
}
|
||||
}
|
||||
itSecondNeighbor++;
|
||||
++itSecondNeighbor;
|
||||
}
|
||||
}
|
||||
itFirstNeighbor++;
|
||||
++itFirstNeighbor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,3 +116,72 @@ bool LanParty::canProcessVertex(const int vertexToCheck, const int vertexTx) con
|
||||
const std::string& label{ lan_.getVertexData(vertexToCheck) };
|
||||
return (label[0] != 't' || label > lan_.getVertexData(vertexTx));
|
||||
}
|
||||
|
||||
bool LanParty::findCompleteSubgraph(const int vertex, const size_t targetSize)
|
||||
{
|
||||
// Validates that the degree of the start vertex is actually high enough for the target clique size.
|
||||
if (targetSize > lan_.getDegree(vertex) + 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Neighbors of start vertex.
|
||||
std::vector<int> neighbors{};
|
||||
neighbors.reserve(lan_.getDegree(vertex));
|
||||
auto it = lan_.begin(vertex);
|
||||
while (it != lan_.end())
|
||||
{
|
||||
neighbors.push_back(it->vertex);
|
||||
++it;
|
||||
}
|
||||
|
||||
// Combination of neighbors, i.e. 'neighbor[i]' is selected if and only if 'combination[i]' is true.
|
||||
std::vector<bool> combination(targetSize - 1, true);
|
||||
combination.resize(neighbors.size());
|
||||
|
||||
do
|
||||
{
|
||||
if (isSubgraphComplete(neighbors, combination))
|
||||
{
|
||||
part2 = calcPassword(neighbors, combination, vertex);
|
||||
return true;
|
||||
}
|
||||
} while (std::prev_permutation(combination.begin(), combination.end()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LanParty::isSubgraphComplete(const std::vector<int>& neighbors, const std::vector<bool>& combination) const
|
||||
{
|
||||
for (size_t i = 0; i < combination.size(); ++i)
|
||||
{
|
||||
if (combination[i])
|
||||
{
|
||||
for (size_t j = i + 1; j < combination.size(); ++j)
|
||||
{
|
||||
if (combination[j] && !lan_.areAdjacent(neighbors[i], neighbors[j]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string LanParty::calcPassword(const std::vector<int>& neighbors, const std::vector<bool>& combination,
|
||||
const int vertex) const
|
||||
{
|
||||
std::vector<std::string> completeSubgraph{ lan_.getVertexData(vertex) };
|
||||
|
||||
for (size_t i = 0; i < combination.size(); ++i)
|
||||
{
|
||||
if (combination[i])
|
||||
{
|
||||
completeSubgraph.push_back(lan_.getVertexData(neighbors[i]));
|
||||
}
|
||||
}
|
||||
std::sort(completeSubgraph.begin(), completeSubgraph.end());
|
||||
return std::accumulate(++completeSubgraph.begin(), completeSubgraph.end(), *completeSubgraph.begin(),
|
||||
[](const std::string& acc, const std::string& x) { return acc + "," + x; });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user