Advertisement
Guest User

Untitled

a guest
Sep 25th, 2021
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.29 KB | None | 0 0
  1. #include <algorithm>
  2. #include <iostream>
  3. #include <stdexcept>
  4. #include <vector>
  5.  
  6. enum class Category
  7. {
  8.     Nothing,
  9.     DivisibleBy3,
  10.     DivisibleBy5,
  11.     DivisibleBy3And5
  12. };
  13.  
  14. /// Checks if the given number satisfies the given category.
  15. bool IsAssignationCorrect(Category category, int x)
  16. {
  17.     switch (category)
  18.     {
  19.         case Category::Nothing:
  20.             return x % 3 != 0 && x % 5 != 0;
  21.         case Category::DivisibleBy3:
  22.             return x % 3 == 0 && x % 5 != 0;
  23.         case Category::DivisibleBy5:
  24.             return x % 3 != 0 && x % 5 == 0;
  25.         case Category::DivisibleBy3And5:
  26.             return x % 3 == 0 && x % 5 == 0;
  27.     }
  28.  
  29.     throw std::runtime_error("IsAssignationCorrect: Something really bad happens here!");
  30. }
  31.  
  32. /// Computes the factorial of the given number. This function is normal, no need to be stupid without a reason.
  33. uint64_t ComputeFactorial(uint64_t n)
  34. {
  35.     uint64_t result = 1;
  36.     for (uint64_t i = 1; i <= n; ++i)
  37.         result *= i;
  38.     return result;
  39. }
  40.  
  41. /// Processes an assignation of sets to the given permutation of numbers.
  42. void ProcessAssignation(std::vector<Category> const& assigned_set, std::vector<int> const& numbers)
  43. {
  44.     // So far we have complexity \Theta(n! * 4^n).
  45.  
  46.     // Now, we will only consider the set assignation valid if it is sorted, i.e. we have first
  47.     // all the "Nothing", then all then "DivisibleBy3", and so on. This will not dominate the asymptotic cost,
  48.     // so no reason to be stupid.
  49.     bool is_sorted = true;
  50.     for (std::size_t i = 1; i < assigned_set.size(); ++i)
  51.         is_sorted = is_sorted && assigned_set[i - 1] <= assigned_set[i];
  52.  
  53.     if (!is_sorted)
  54.         return;
  55.  
  56.     // Now that we now that the sets make sense with our restrictions, check that the assignation is correct.
  57.     bool is_assignation_correct = true;
  58.     for (std::size_t i = 0; i < assigned_set.size(); ++i)
  59.         is_assignation_correct = is_assignation_correct && IsAssignationCorrect(assigned_set[i], numbers[i]);
  60.  
  61.     if (!is_assignation_correct)
  62.         return;
  63.  
  64.     // We have a valid assignation of the numbers, and they are sorted by groups. However, we only accept the permutation
  65.     // if the numbers themselves are sorted within each group.
  66.     bool are_numbers_sorted = true;
  67.     for (std::size_t i = 1; i < assigned_set.size(); ++i)
  68.     {
  69.         if (assigned_set[i - 1] == assigned_set[i])
  70.             are_numbers_sorted = are_numbers_sorted && numbers[i - 1] < numbers[i];
  71.     }
  72.  
  73.     if (!are_numbers_sorted)
  74.         return;
  75.  
  76.     // Now print them, but we want them sorted, so we need to sort them first. But let us sort them by trying each possible permutation.
  77.     std::vector<std::pair<int, Category>> output(assigned_set.size());
  78.     for (std::size_t i = 0; i < output.size(); ++i)
  79.         output[i] = std::make_pair(numbers[i], assigned_set[i]);
  80.  
  81.     // This dominates the cost of this function, being \Theta(n!). Thus, the total cost of the algorithm is \Theta((n!)^2 * 4^n).
  82.     while (std::next_permutation(output.begin(), output.end())) { }
  83.  
  84.     for (auto const& [x, category] : output)
  85.     {
  86.         switch (category)
  87.         {
  88.             case Category::Nothing:
  89.                 std::cout << x << std::endl;
  90.                 break;
  91.             case Category::DivisibleBy3:
  92.                 std::cout << "Fizz" << std::endl;
  93.                 break;
  94.             case Category::DivisibleBy5:
  95.                 std::cout << "Buzz" << std::endl;
  96.                 break;
  97.             case Category::DivisibleBy3And5:
  98.                 std::cout << "FizzBuzz" << std::endl;
  99.                 break;
  100.         }
  101.     }
  102. }
  103.  
  104. /// Backtracking that assigns one category to each element of @p assigned_set with index greater or equal than @p current_index.
  105. void AssignSets(std::size_t current_index, std::vector<Category>& assigned_set, std::vector<int> const& numbers)
  106. {
  107.     if (current_index == assigned_set.size())
  108.     {
  109.         // We reached a complete assignation, so process it.
  110.         ProcessAssignation(assigned_set, numbers);
  111.         return;
  112.     }
  113.  
  114.     // Assign each possible category.
  115.     for (std::size_t i = 0; i < 4; ++i)
  116.     {
  117.         assigned_set[current_index] = static_cast<Category>(i);
  118.         AssignSets(current_index + 1, assigned_set, numbers);
  119.     }
  120. }
  121.  
  122. int main(int argc, char** argv)
  123. {
  124.     if (argc < 2)
  125.     {
  126.         std::cout << "Usage: executable n" << std::endl;
  127.         return 0;
  128.     }
  129.  
  130.     int n = std::atoi(argv[1]);
  131.  
  132.     // Start by pushing the numbers to a vector.
  133.     std::vector<int> numbers(n);
  134.     std::generate(numbers.begin(), numbers.end(), [i = n] () mutable { return i--; });
  135.     std::random_shuffle(numbers.begin(), numbers.end());
  136.  
  137.     // Iterate through all the permutations of the vector: \Theta(n!)
  138.     uint64_t n_factorial = ComputeFactorial(n);
  139.     for (uint64_t i = 0; i < n_factorial; ++i)
  140.     {
  141.         std::next_permutation(numbers.begin(), numbers.end());
  142.  
  143.         // Now we want to assign each number to one of the possible 4 groups:
  144.         // nothing, divisible by 3, divisible by 5, divisible by 3 and 5.
  145.         // This takes \Theta(4^n) without considering what we will be doing once each assignation is computed.
  146.         std::vector<Category> assigned_set(n);
  147.         AssignSets(/*current_index*/ 0, assigned_set, numbers);
  148.     }
  149. }
  150.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement