155 lines
4.6 KiB
C++
155 lines
4.6 KiB
C++
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <fstream>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <list>
|
|
#include <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
constexpr std::size_t STEP_COUNT = 1000;
|
|
constexpr std::size_t TOP_N_COUNT = 3;
|
|
|
|
// Just for clean code sake, This is doable without structs or classes
|
|
typedef double Distance;
|
|
struct Junction;
|
|
|
|
struct Cluster {
|
|
std::vector<Junction *> members{};
|
|
};
|
|
|
|
struct Junction {
|
|
int64_t x, y, z;
|
|
Cluster *parentCluster = nullptr;
|
|
};
|
|
|
|
Distance distanceBetween(Junction first, Junction second) {
|
|
return std::sqrt(std::pow(second.x - first.x, 2) +
|
|
std::pow(second.y - first.y, 2) +
|
|
std::pow(second.z - first.z, 2));
|
|
}
|
|
|
|
int main() {
|
|
std::fstream input("input");
|
|
std::string currentLine = "";
|
|
std::vector<Junction> junctionList{};
|
|
std::list<Cluster> clusterList{};
|
|
std::multimap<Distance, std::pair<Junction *, Junction *>>
|
|
junctionDistanceMap{};
|
|
uint64_t junctionListSize = 0;
|
|
|
|
// I do think we could process text and do the necessary calculations for the
|
|
// solution, but once again, code should be preferably legiable
|
|
while (std::getline(input, currentLine, '\n')) {
|
|
uint16_t positionOfFirstComma, positionOfSecondComma;
|
|
positionOfFirstComma = currentLine.find(',');
|
|
positionOfSecondComma = currentLine.find(',', positionOfFirstComma + 1);
|
|
|
|
int64_t x, y, z;
|
|
x = std::stoll(currentLine.substr(0, positionOfFirstComma));
|
|
y = std::stoll(
|
|
currentLine.substr(positionOfFirstComma + 1,
|
|
positionOfSecondComma - positionOfFirstComma));
|
|
z = std::stoll(currentLine.substr(positionOfSecondComma + 1));
|
|
|
|
junctionList.push_back({x, y, z});
|
|
}
|
|
|
|
// This is O(n²), ouch. It can be estimated with T_n, So idk maybe O(T_n)
|
|
uint64_t count = 0;
|
|
junctionListSize = junctionList.size();
|
|
for (Junction &junction : junctionList) {
|
|
for (uint64_t index = ++count; index < junctionListSize; index++) {
|
|
junctionDistanceMap.insert(
|
|
{distanceBetween(junction, junctionList[index]),
|
|
{&junction, &junctionList[index]}});
|
|
}
|
|
}
|
|
|
|
// Ordered by smallest to largest key
|
|
count = std::min(STEP_COUNT, junctionDistanceMap.size());
|
|
for (const auto &Key : junctionDistanceMap) {
|
|
if (count == 0) {
|
|
break;
|
|
}
|
|
count--;
|
|
|
|
Junction *first = Key.second.first, *second = Key.second.second;
|
|
Cluster *firstCluster = first->parentCluster,
|
|
*secondCluster = second->parentCluster;
|
|
// 4 real possibilities
|
|
bool firstHasACluster = firstCluster != nullptr,
|
|
secondHasACluster = secondCluster != nullptr;
|
|
|
|
// Both have clusters, merge clusters
|
|
if (firstHasACluster && secondHasACluster) {
|
|
// Since both are already connected
|
|
if (firstCluster == secondCluster) {
|
|
continue;
|
|
}
|
|
|
|
// This bad boy merges the clusters and updates the pointers
|
|
firstCluster->members.insert(firstCluster->members.end(),
|
|
secondCluster->members.begin(),
|
|
secondCluster->members.end());
|
|
|
|
for (Junction *clusterJunction : secondCluster->members) {
|
|
clusterJunction->parentCluster = firstCluster;
|
|
}
|
|
|
|
// Temp fix
|
|
secondCluster->members.clear();
|
|
second->parentCluster = firstCluster;
|
|
|
|
continue;
|
|
}
|
|
|
|
// Both don't have clusters, pair up
|
|
if (!firstHasACluster && !secondHasACluster) {
|
|
clusterList.push_back({{first, second}});
|
|
// Directly writing, can't use the variable here
|
|
first->parentCluster = &clusterList.back();
|
|
second->parentCluster = &clusterList.back();
|
|
continue;
|
|
}
|
|
|
|
// Only first doesn't have it, append to second
|
|
if (!firstHasACluster) {
|
|
first->parentCluster = secondCluster;
|
|
secondCluster->members.push_back(first);
|
|
continue;
|
|
}
|
|
|
|
// Only second doesn't have it, append to first
|
|
if (!secondHasACluster) {
|
|
second->parentCluster = firstCluster;
|
|
firstCluster->members.push_back(second);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Multiset is preferable
|
|
std::multiset<uint64_t, std::greater<uint64_t>> clusterSize{};
|
|
for (const Cluster &cluster : clusterList) {
|
|
uint64_t size = cluster.members.size();
|
|
if (size == 0) {
|
|
continue;
|
|
}
|
|
clusterSize.insert(size);
|
|
}
|
|
|
|
// I'm so tired of this question
|
|
auto iterator = clusterSize.begin();
|
|
uint64_t password = *iterator;
|
|
for (uint16_t index = 0; index < TOP_N_COUNT - 1; index++) {
|
|
iterator++;
|
|
password *= *iterator;
|
|
}
|
|
std::cout << password << "\n";
|
|
}
|