2018-02-19 15:21:05 +01:00
|
|
|
# Copyright 2010 Hakan Kjellerstrand hakank@gmail.com
|
2010-10-14 06:16:18 +00:00
|
|
|
#
|
2012-01-16 10:40:52 +00:00
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
|
# You may obtain a copy of the License at
|
2010-10-14 06:16:18 +00:00
|
|
|
#
|
2012-01-16 10:40:52 +00:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2010-10-14 06:16:18 +00:00
|
|
|
#
|
2012-01-16 10:40:52 +00:00
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
|
# limitations under the License.
|
2010-10-14 06:16:18 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
Langford's number problem in Google CP Solver.
|
|
|
|
|
|
|
|
|
|
Langford's number problem (CSP lib problem 24)
|
|
|
|
|
http://www.csplib.org/prob/prob024/
|
|
|
|
|
'''
|
|
|
|
|
Arrange 2 sets of positive integers 1..k to a sequence,
|
2012-01-16 10:40:52 +00:00
|
|
|
such that, following the first occurence of an integer i,
|
2010-10-14 06:16:18 +00:00
|
|
|
each subsequent occurrence of i, appears i+1 indices later
|
2012-01-16 10:40:52 +00:00
|
|
|
than the last.
|
2010-10-14 06:16:18 +00:00
|
|
|
For example, for k=4, a solution would be 41312432
|
|
|
|
|
'''
|
2012-01-16 10:40:52 +00:00
|
|
|
|
2010-10-14 06:16:18 +00:00
|
|
|
* John E. Miller: Langford's Problem
|
|
|
|
|
http://www.lclark.edu/~miller/langford.html
|
2012-01-16 10:40:52 +00:00
|
|
|
|
2010-10-14 06:16:18 +00:00
|
|
|
* Encyclopedia of Integer Sequences for the number of solutions for each k
|
|
|
|
|
http://www.research.att.com/cgi-bin/access.cgi/as/njas/sequences/eisA.cgi?Anum=014552
|
2012-01-16 10:40:52 +00:00
|
|
|
|
2010-10-14 06:16:18 +00:00
|
|
|
|
|
|
|
|
Also, see the following models:
|
|
|
|
|
* MiniZinc: http://www.hakank.org/minizinc/langford2.mzn
|
|
|
|
|
* Gecode/R: http://www.hakank.org/gecode_r/langford.rb
|
|
|
|
|
* ECLiPSe: http://hakank.org/eclipse/langford.ecl
|
|
|
|
|
* SICStus: http://hakank.org/sicstus/langford.pl
|
|
|
|
|
|
|
|
|
|
|
2018-02-19 15:21:05 +01:00
|
|
|
This model was created by Hakan Kjellerstrand (hakank@gmail.com)
|
2014-05-22 20:13:16 +00:00
|
|
|
Also see my other Google CP Solver models:
|
|
|
|
|
http://www.hakank.org/google_or_tools/
|
2010-10-14 06:16:18 +00:00
|
|
|
"""
|
2016-01-14 18:59:36 +01:00
|
|
|
from __future__ import print_function
|
2010-10-14 06:16:18 +00:00
|
|
|
import sys
|
|
|
|
|
|
2013-12-24 11:35:01 +00:00
|
|
|
from ortools.constraint_solver import pywrapcp
|
2010-10-14 06:16:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(k=8, num_sol=0):
|
2012-01-16 10:40:52 +00:00
|
|
|
|
2014-05-22 20:13:16 +00:00
|
|
|
# Create the solver.
|
|
|
|
|
solver = pywrapcp.Solver("Langford")
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# data
|
|
|
|
|
#
|
2016-01-14 18:59:36 +01:00
|
|
|
print("k:", k)
|
|
|
|
|
p = list(range(2 * k))
|
2014-05-22 20:13:16 +00:00
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# declare variables
|
|
|
|
|
#
|
|
|
|
|
position = [solver.IntVar(0, 2 * k - 1, "position[%i]" % i) for i in p]
|
|
|
|
|
solution = [solver.IntVar(1, k, "position[%i]" % i) for i in p]
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# constraints
|
|
|
|
|
#
|
|
|
|
|
solver.Add(solver.AllDifferent(position))
|
|
|
|
|
|
|
|
|
|
for i in range(1, k + 1):
|
|
|
|
|
solver.Add(position[i + k - 1] == position[i - 1] + i + 1)
|
|
|
|
|
solver.Add(solver.Element(solution, position[i - 1]) == i)
|
|
|
|
|
solver.Add(solver.Element(solution, position[k + i - 1]) == i)
|
|
|
|
|
|
|
|
|
|
# symmetry breaking
|
|
|
|
|
solver.Add(solution[0] < solution[2 * k - 1])
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# search and result
|
|
|
|
|
#
|
2018-06-11 11:51:18 +02:00
|
|
|
db = solver.Phase(position, solver.CHOOSE_FIRST_UNBOUND,
|
2014-05-22 20:13:16 +00:00
|
|
|
solver.ASSIGN_MIN_VALUE)
|
|
|
|
|
|
|
|
|
|
solver.NewSearch(db)
|
|
|
|
|
num_solutions = 0
|
|
|
|
|
while solver.NextSolution():
|
2016-01-14 18:59:36 +01:00
|
|
|
print("solution:", ",".join([str(solution[i].Value()) for i in p]))
|
2014-05-22 20:13:16 +00:00
|
|
|
num_solutions += 1
|
|
|
|
|
if num_sol > 0 and num_solutions >= num_sol:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
solver.EndSearch()
|
|
|
|
|
|
2016-01-14 18:59:36 +01:00
|
|
|
print()
|
|
|
|
|
print("num_solutions:", num_solutions)
|
|
|
|
|
print("failures:", solver.Failures())
|
|
|
|
|
print("branches:", solver.Branches())
|
|
|
|
|
print("WallTime:", solver.WallTime())
|
2010-10-14 06:16:18 +00:00
|
|
|
|
2018-06-11 11:51:18 +02:00
|
|
|
|
2010-10-14 06:16:18 +00:00
|
|
|
k = 8
|
|
|
|
|
num_sol = 0
|
2014-05-22 20:13:16 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
|
if len(sys.argv) > 1:
|
2015-12-15 23:59:46 -08:00
|
|
|
k = int(sys.argv[1])
|
2014-05-22 20:13:16 +00:00
|
|
|
if len(sys.argv) > 2:
|
2015-12-15 23:59:46 -08:00
|
|
|
num_sol = int(sys.argv[2])
|
2012-01-16 10:40:52 +00:00
|
|
|
|
2014-05-22 20:13:16 +00:00
|
|
|
main(k, num_sol)
|