-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
Copy pathmagic_sequence.cpp
136 lines (126 loc) · 4.15 KB
/
magic_sequence.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
* @brief [Magic sequence](https://www.csplib.org/Problems/prob019/)
* implementation
*
* @details Solve the magic sequence problem with backtracking
*
* "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 taken from the [CSPLib](https://www.csplib.org/Problems/prob019/)
* website
*
* @author [Jxtopher](https://github.com/Jxtopher)
*/
#include <algorithm> /// for std::count
#include <cassert> /// for assert
#include <iostream> /// for IO operations
#include <list> /// for std::list
#include <numeric> /// for std::accumulate
#include <vector> /// for std::vector
/**
* @namespace backtracking
* @brief Backtracking algorithms
*/
namespace backtracking {
/**
* @namespace magic_sequence
* @brief Functions for the [Magic
* sequence](https://www.csplib.org/Problems/prob019/) implementation
*/
namespace magic_sequence {
using sequence_t =
std::vector<unsigned int>; ///< Definition of the sequence type
/**
* @brief Print the magic sequence
* @param s working memory for the sequence
*/
void print(const sequence_t& s) {
for (const auto& item : s) std::cout << item << " ";
std::cout << std::endl;
}
/**
* @brief Check if the sequence is magic
* @param s working memory for the sequence
* @returns true if it's a magic sequence
* @returns false if it's NOT a magic sequence
*/
bool is_magic(const sequence_t& s) {
for (unsigned int i = 0; i < s.size(); i++) {
if (std::count(s.cbegin(), s.cend(), i) != s[i]) {
return false;
}
}
return true;
}
/**
* @brief Sub-solutions filtering
* @param s working memory for the sequence
* @param depth current depth in tree
* @returns true if the sub-solution is valid
* @returns false if the sub-solution is NOT valid
*/
bool filtering(const sequence_t& s, unsigned int depth) {
return std::accumulate(s.cbegin(), s.cbegin() + depth,
static_cast<unsigned int>(0)) <= s.size();
}
/**
* @brief Solve the Magic Sequence problem
* @param s working memory for the sequence
* @param ret list of the valid magic sequences
* @param depth current depth in the tree
*/
void solve(sequence_t* s, std::list<sequence_t>* ret, unsigned int depth = 0) {
if (depth == s->size()) {
if (is_magic(*s)) {
ret->push_back(*s);
}
} else {
for (unsigned int i = 0; i < s->size(); i++) {
(*s)[depth] = i;
if (filtering(*s, depth + 1)) {
solve(s, ret, depth + 1);
}
}
}
}
} // namespace magic_sequence
} // namespace backtracking
/**
* @brief Self-test implementations
* @returns void
*/
static void test() {
// test a valid magic sequence
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));
// test a non-valid magic sequence
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));
}
/**
* @brief Main function
* @returns 0 on exit
*/
int main() {
test(); // run self-test implementations
// solve magic sequences of size 2 to 11 and print the solutions
for (unsigned int i = 2; i < 12; i++) {
std::cout << "Solution for n = " << i << std::endl;
// valid magic sequence list
std::list<backtracking::magic_sequence::sequence_t> list_of_solutions;
// initialization of a sequence
backtracking::magic_sequence::sequence_t s1(i, i);
// launch of solving the problem
backtracking::magic_sequence::solve(&s1, &list_of_solutions);
// print solutions
for (const auto& item : list_of_solutions) {
backtracking::magic_sequence::print(item);
}
}
return 0;
}