问题描述
我有“n”张桌子和“m”个盒子。 任务是把所有的盒子堆在桌子上。
问题: 有哪些不同的可能组合? 重要提示:所有的盒子放在桌子上时都是有序的,就像堆叠一样。我需要知道堆栈中每个盒子的排名。
如何使用 ORTOOL 约束编程 / SAT 来实现该问题? 什么是最好的策略?什么变量/约束?
(我不期待代码,但只是建议......除非你是一个快速的开发者:) 谢谢
from ortools.sat.python import cp_model
class VararraySolutionPrinter(cp_model.cpsolverSolutionCallback):
def __init__(self,variables):
cp_model.cpsolverSolutionCallback.__init__(self)
self.__variables = variables
self.__solution_count = 0
def on_solution_callback(self):
self.__solution_count += 1
for v in self.__variables:
print('%s=%i' % (v,self.Value(v)))
print("")
def solution_count(self):
return self.__solution_count
def main():
variables = []
model = cp_model.CpModel()
#################################################
nb_tables = 3
nb_Boxes = 4
for Box in range(nb_Boxes):
Box_to_table = model.NewIntvar(0,nb_tables - 1,'Box_'+str(Box)+'_to_table')
variables.append(Box_to_table)
ranking_variables = []
for Box in range(nb_Boxes):
rank_of_Box_on_its_table = model.NewIntvar(0,nb_Boxes - 1,'rank_of_Box_'+str(Box)+'_on_its_table')
variables.append(rank_of_Box_on_its_table)
ranking_variables.append(rank_of_Box_on_its_table)
# the next line is not good because the ranking is global
# and not local to each table. how to manage that?
model.AddAllDifferent(ranking_variables)
#################################################
solver = cp_model.cpsolver()
solution_printer = VararraySolutionPrinter(variables)
status = solver.SearchForAllSolutions(model,solution_printer)
print('Status = %s' % solver.StatusName(status))
print('Number of solutions found: %i' % solution_printer.solution_count())
main()
还有布尔版本:
#################################################
nb_tables = 3
nb_Boxes = 4
for Box in range(nb_Boxes):
this_Box_vars = []
for table in range(nb_tables):
Box_in_table = model.NewBoolVar('Box_'+str(Box)+'_in_table_' + str(table))
variables.append(Box_in_table)
this_Box_vars.append(Box_in_table)
model.Add(sum(this_Box_vars) == 1)
ranking_variables = []
for Box in range(nb_Boxes):
rank_of_Box_on_its_table = model.NewIntvar(0,'rank_of_Box_'+str(Box)+'_on_its_table')
variables.append(rank_of_Box_on_its_table)
ranking_variables.append(rank_of_Box_on_its_table)
# the next line is not good because the ranking is global
# and not local to each table. how to manage that?
model.AddAllDifferent(ranking_variables)
#################################################
解决方法
不要使用整数变量。
经验法则:
- 如果您看到 AllDifferent 约束,请将其删除,并用布尔变量列表替换整数变量。
- 加总和(bool_vars) == 1
x[i][j][k]
是一个布尔变量,表示框 i 在表 j 上的位置 k。
y[j][k]
表示表 j 中位置 k 处是否有一个框。
每个框只出现一次:
forall i: Sum on j,k box[i][j][k] == 1
每个位置最多被一个盒子占据:
forall j,k: sum on i box[i][k][k] <= 1
如果某个盒子在某处,则表示该某处已被占用:
forall i,j,k: box[i][j][k] implies y[j][k]
如果一个位置被占用,这个位置一定有一个框:
forall j,k: bool_or([y[j][k].Not(),box[0][j][k],..,box[n - 1][j][k]])
表上的位置必须从 0 开始密集占用:
forall j,k (except last position): y[j][k].Not() implies y[j][k + 1].Not()
如果你想要一个盒子的排名
forall i: rank[i] == sum over j,k box[i][j][k] * k