131 lines
3.4 KiB
C++
Raw Normal View History

2021-07-11 06:43:45 +02:00
/*
* @brief [Magic sequence](https://www.csplib.org/Problems/prob019/) implementation
2021-07-11 06:43:45 +02:00
*
2021-07-12 18:54:48 +02:00
* @details Solve the magic sequence problem with a backtraking
*
* "A magic sequence of length $n$ is a sequence of integers $x_0
* \ldots x_{n-1}$ between $0$ and $n-1$, such that for all $i$
* in $0$ to $n-1$, the number $i$ occurs exactly $x_i$ times in
* the sequence. For instance, $6,2,1,0,0,0,1,0,0,0$ is a magic
* sequence since $0$ occurs $6$ times in it, $1$ occurs twice, etc."
* Quote of https://www.csplib.org/Problems/prob019/
2021-07-11 06:43:45 +02:00
*
* @author [Jxtopher](https://github.com/jxtopher)
*/
2021-07-12 18:54:48 +02:00
#include <algorithm> /// std::count
#include <cassert> /// assert
#include <iostream> /// IO operations
#include <list> /// std::list
#include <numeric> /// std::accumulate
#include <vector> /// std::vector
2021-07-11 06:43:45 +02:00
2021-07-12 18:54:48 +02:00
/**
* @namespace
* @brief Backtracking algorithms
*/
2021-07-11 06:43:45 +02:00
namespace backtracking {
2021-07-12 18:54:48 +02:00
/**
* @namespace
* @brief Definition and solve magic sequence problem
*/
2021-07-11 06:43:45 +02:00
namespace magic_sequence {
2021-07-11 22:52:18 +02:00
using sequence_t = std::vector<unsigned int>;
2021-07-11 06:43:45 +02:00
2021-07-12 18:54:48 +02:00
/**
* @brief print a magic sequence
*
* @param s a magic sequence
*/
2021-07-11 22:52:18 +02:00
void print(const sequence_t& s) {
for (const auto& item : s) std::cout << item << " ";
std::cout << std::endl;
}
2021-07-11 06:43:45 +02:00
2021-07-12 18:54:48 +02:00
/**
* @brief Check if it's a magic sequence
*
* @param s a magic sequence
* @return true if is a magic sequence
* @return false otherwise
*
*/
2021-07-11 22:52:18 +02:00
bool is_magic(const sequence_t& s) {
for (unsigned int i = 0; i < s.size(); i++) {
2021-07-11 23:21:43 +02:00
if (std::count(s.cbegin(), s.cend(), i) != s[i]) {
2021-07-11 22:52:18 +02:00
return false;
2021-07-11 23:21:43 +02:00
}
2021-07-11 06:43:45 +02:00
}
2021-07-11 22:52:18 +02:00
return true;
}
2021-07-11 06:43:45 +02:00
2021-07-12 18:54:48 +02:00
/**
* @brief Filtering of sub-solutions
*
* @param s a magic sequence
* @param depth
* @return true if the sub-solution is valid
* @return false otherwise
*
*/
2021-07-11 22:52:18 +02:00
bool filtering(const sequence_t& s, unsigned int depth) {
return std::accumulate(s.cbegin(), s.cbegin() + depth,
static_cast<unsigned int>(0)) <= s.size();
}
2021-07-11 06:43:45 +02:00
2021-07-12 18:54:48 +02:00
/**
* @brief solve magic squance problem
*
* @param s a magic sequence
* @param ret list of valid magic sequences
* @param depth depth in the tree
*
*/
2021-07-11 22:52:18 +02:00
void solve(sequence_t* s, std::list<sequence_t>* ret, unsigned int depth = 0) {
if (depth == s->size()) {
2021-07-11 23:21:43 +02:00
if (is_magic(*s)) {
2021-07-11 22:52:18 +02:00
ret->push_back(*s);
2021-07-11 23:21:43 +02:00
}
2021-07-11 22:52:18 +02:00
} else {
for (unsigned int i = 0; i < s->size(); i++) {
(*s)[depth] = i;
2021-07-11 23:21:43 +02:00
if (filtering(*s, depth + 1)) {
2021-07-11 22:52:18 +02:00
solve(s, ret, depth + 1);
2021-07-11 23:21:43 +02:00
}
2021-07-11 06:43:45 +02:00
}
}
2021-07-11 22:52:18 +02:00
}
2021-07-11 06:43:45 +02:00
2021-07-11 22:52:18 +02:00
} // namespace magic_sequence
2021-07-11 06:43:45 +02:00
2021-07-11 22:52:18 +02:00
} // namespace backtracking
2021-07-11 06:43:45 +02:00
2021-07-12 18:54:48 +02:00
/**
* @brief tests
*
*/
2021-07-11 06:43:45 +02:00
static void test() {
2021-07-11 23:21:43 +02:00
backtracking::magic_sequence::sequence_t s_magic = {6, 2, 1, 0, 0,
0, 1, 0, 0, 0};
assert(backtracking::magic_sequence::is_magic(s_magic));
2021-07-11 06:43:45 +02:00
2021-07-11 23:21:43 +02:00
backtracking::magic_sequence::sequence_t s_not_magic = {5, 2, 1, 0, 0,
0, 1, 0, 0, 0};
assert(!backtracking::magic_sequence::is_magic(s_not_magic));
2021-07-11 06:43:45 +02:00
}
int main() {
test();
2021-07-11 22:52:18 +02:00
for (unsigned int i = 2; i < 12; i++) {
2021-07-11 06:43:45 +02:00
std::cout << "Solution for n = " << i << std::endl;
2021-07-11 23:21:43 +02:00
std::list<backtracking::magic_sequence::sequence_t> r1;
backtracking::magic_sequence::sequence_t s1(i, i);
backtracking::magic_sequence::solve(&s1, &r1);
for (const auto& item : r1) backtracking::magic_sequence::print(item);
2021-07-11 06:43:45 +02:00
}
}