158 lines
3.4 KiB
C++
158 lines
3.4 KiB
C++
#include <algorithm>
|
||
#include <cmath>
|
||
#include <unordered_map>
|
||
#include <vector>
|
||
|
||
namespace {
|
||
struct factors_iterator {
|
||
factors_iterator() : f(-1) {}
|
||
factors_iterator(int f, int n) : f(f), n(n), upper(std::sqrt(n)) {}
|
||
|
||
auto operator!=(const factors_iterator &other) const -> bool {
|
||
return f != other.f;
|
||
}
|
||
|
||
auto operator*() const -> int { return f; }
|
||
|
||
auto operator++() -> factors_iterator & {
|
||
// ‹f› yielded a prime
|
||
if (f > upper || n == 1) {
|
||
f = -1;
|
||
return *this;
|
||
}
|
||
|
||
do {
|
||
++f;
|
||
} while (f <= upper && n % f != 0);
|
||
|
||
// ‹n› is a prime
|
||
if (f > upper) {
|
||
f = n;
|
||
}
|
||
|
||
while (n % f == 0) {
|
||
n /= f;
|
||
}
|
||
|
||
return *this;
|
||
}
|
||
|
||
private:
|
||
int f;
|
||
int n;
|
||
int upper;
|
||
};
|
||
|
||
struct factors {
|
||
factors(int n) : n(n) {}
|
||
auto begin() const -> factors_iterator { return ++factors_iterator(1, n); }
|
||
auto end() const -> factors_iterator { return factors_iterator(); }
|
||
|
||
private:
|
||
int n;
|
||
};
|
||
|
||
void dfs(std::unordered_map<int, std::vector<int>> &graph,
|
||
std::vector<bool> &visited, int u) {
|
||
visited[u] = true;
|
||
for (auto v : graph[u]) {
|
||
if (!visited[v]) {
|
||
dfs(graph, visited, v);
|
||
}
|
||
}
|
||
}
|
||
} // namespace
|
||
|
||
class Solution {
|
||
public:
|
||
bool canTraverseAllPairs(const std::vector<int> &nums) {
|
||
auto n = nums.size();
|
||
|
||
std::unordered_map<int, int> gcd;
|
||
std::unordered_map<int, std::vector<int>> neighbors;
|
||
|
||
for (auto i = 0u; i < n; ++i) {
|
||
for (auto f : factors(nums[i])) {
|
||
if (gcd.contains(f)) {
|
||
int u = i;
|
||
int v = gcd[f];
|
||
neighbors[u].push_back(v);
|
||
neighbors[v].push_back(u);
|
||
}
|
||
|
||
gcd[f] = i;
|
||
}
|
||
}
|
||
|
||
std::vector<bool> visited(n, false);
|
||
dfs(neighbors, visited, 0);
|
||
|
||
return std::find(visited.begin(), visited.end(), false) ==
|
||
visited.end();
|
||
}
|
||
};
|
||
|
||
#ifdef _MF_TEST
|
||
#include <gtest/gtest.h>
|
||
|
||
TEST(examples, no_1) {
|
||
Solution s;
|
||
EXPECT_TRUE(s.canTraverseAllPairs(std::vector{2, 3, 6}));
|
||
}
|
||
TEST(examples, no_2) {
|
||
Solution s;
|
||
EXPECT_FALSE(s.canTraverseAllPairs(std::vector{3, 9, 5}));
|
||
}
|
||
TEST(examples, no_3) {
|
||
Solution s;
|
||
EXPECT_TRUE(s.canTraverseAllPairs(std::vector{4, 3, 12, 8}));
|
||
}
|
||
|
||
TEST(factors, prime_2) {
|
||
std::vector<int> fs;
|
||
for (auto f : factors(2)) {
|
||
fs.push_back(f);
|
||
}
|
||
EXPECT_EQ(fs, std::vector{2});
|
||
}
|
||
TEST(factors, prime_7) {
|
||
std::vector<int> fs;
|
||
for (auto f : factors(7)) {
|
||
fs.push_back(f);
|
||
}
|
||
EXPECT_EQ(fs, std::vector{7});
|
||
}
|
||
TEST(factors, prime_29) {
|
||
std::vector<int> fs;
|
||
for (auto f : factors(29)) {
|
||
fs.push_back(f);
|
||
}
|
||
EXPECT_EQ(fs, std::vector{29});
|
||
}
|
||
TEST(factors, composite_6) {
|
||
std::vector<int> fs;
|
||
for (auto f : factors(6)) {
|
||
fs.push_back(f);
|
||
}
|
||
EXPECT_EQ(fs, (std::vector{2, 3}));
|
||
}
|
||
TEST(factors, composite_15) {
|
||
std::vector<int> fs;
|
||
for (auto f : factors(15)) {
|
||
fs.push_back(f);
|
||
}
|
||
EXPECT_EQ(fs, (std::vector{3, 5}));
|
||
}
|
||
TEST(factors, composite_1024) {
|
||
std::vector<int> fs;
|
||
for (auto f : factors(1024)) {
|
||
fs.push_back(f);
|
||
}
|
||
EXPECT_EQ(fs, std::vector{2});
|
||
}
|
||
|
||
int main(int argc, char **argv) {
|
||
testing::InitGoogleTest(&argc, argv);
|
||
return RUN_ALL_TESTS();
|
||
}
|
||
#endif
|