Download
/*
Set partition problem in Gecode.
Problem formulation from
http://www.koalog.com/resources/samples/PartitionProblem.java.html
"""
This is a partition problem.
Given the set S = {1, 2, ..., n},
it consists in finding two sets A and B such that:
- A U B = S,
- |A| = |B|,
- sum(A) = sum(B),
- sum_squares(A) = sum_squares(B).
"""
Compare with my other models:
* MiniZinc: http://www.hakank.org/minizinc/set_partition.mzn
* Gecode/R: http://www.hakank.org/gecode_r/set_partition.rb
* Comet : http://www.hakank.org/comet/set_partition.co
* ECLiPSe : http://www.hakank.org/eclipse/set_partition.ecl
* SICStus Prolog: http://www.hakank.org/sicstus/set_partition.pl
Note: In the Gecode distribution there is a model that solves
the same problem but a different approach.
This current model uses set variables, whereas the distributed
model uses integer variables (and a lot of efficiency constraints).
This Gecode model was created by Hakan Kjellerstrand (hakank@gmail.com)
Also, see my Gecode page: http://www.hakank.org/gecode/ .
*/
// Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/
#include
#include
#include
using namespace Gecode;
using std::cout;
using std::endl;
class SetPartition : public Script {
protected:
static const int num_sets = 2;
int n;
SetVarArray a;
IntVarArray sums;
IntVarArray sum_squared;
public:
SetPartition(const SizeOptions& opt)
:
n(opt.size()),
a(*this, num_sets, IntSet::empty, IntSet(1, n)),
sums(*this, num_sets, 0,n*n),
sum_squared(*this, num_sets, 0,n*n*n)
{
// cardinality of each set
int card = n / num_sets;
// create sets for the weighted sums
IntArgs weights1;
IntArgs weights_squared;
for(int i = 1; i <= n; i++) {
weights1 << i;
weights_squared<< i*i;
}
// use all the elements in S and it should be disjoint sets
for(int i = 0; i < num_sets; i++) {
cardinality(*this, a[i], card, card);
}
// disjoint sets
for(int i = 0; i < num_sets; i++) {
for(int j = 0; j < i; j++) {
rel(*this, a[i] || a[j]);
}
}
// get the sums
for(int i = 0; i < num_sets; i++) {
weights(*this, weights1, weights1, a[i], sums[i]);
weights(*this, weights1, weights_squared, a[i], sum_squared[i]);
}
// the sets have equal sums and equal squared sums
for(int i = 1; i < num_sets; i++) {
rel(*this, sums[i] == sums[i-1]);
rel(*this, sum_squared[i] == sum_squared[i-1]);
}
// symmetry breaking: 1 is in the first set
rel(*this, a[0], SRT_SUP, IntVar(*this,1,1));
branch(*this, a, SET_VAR_SIZE_MAX(), SET_VAL_MAX_INC());
/*
branch(*this, sums, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
branch(*this, sum_squared, INT_VAR_SIZE_MIN(), INT_VAL_MIN());
*/
}
// Print solution
virtual void
print(std::ostream& os) const {
os << "a : " << a << std::endl;
os << "sums : " << sums << std::endl;
os << "sum_squared: " << sum_squared << std::endl;
os << std::endl;
}
// Constructor for cloning s
SetPartition(bool share, SetPartition& s) : Script(share,s), n(s.n) {
a.update(*this, share, s.a);
sums.update(*this, share, s.sums);
sum_squared.update(*this, share, s.sum_squared);
}
// Copy during cloning
virtual Space*
copy(bool share) {
return new SetPartition(share,*this);
}
};
int
main(int argc, char* argv[]) {
SizeOptions opt("SetPartition");
opt.solutions(0);
opt.size(12);
opt.parse(argc,argv);
/*
if (opt.size() % 2 == 1) {
std::cerr << "Size " << opt.size() << " is not even." << endl;
return 1;
}
*/
Script::run(opt);
return 0;
}